scss_lint 0.38.0

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 (157) hide show
  1. checksums.yaml +7 -0
  2. data/bin/scss-lint +6 -0
  3. data/config/default.yml +205 -0
  4. data/data/prefixed-identifiers/base.txt +107 -0
  5. data/data/prefixed-identifiers/bourbon.txt +71 -0
  6. data/data/properties.txt +477 -0
  7. data/data/property-sort-orders/concentric.txt +134 -0
  8. data/data/property-sort-orders/recess.txt +149 -0
  9. data/data/property-sort-orders/smacss.txt +137 -0
  10. data/lib/scss_lint.rb +31 -0
  11. data/lib/scss_lint/cli.rb +215 -0
  12. data/lib/scss_lint/config.rb +251 -0
  13. data/lib/scss_lint/constants.rb +8 -0
  14. data/lib/scss_lint/control_comment_processor.rb +126 -0
  15. data/lib/scss_lint/engine.rb +56 -0
  16. data/lib/scss_lint/exceptions.rb +21 -0
  17. data/lib/scss_lint/file_finder.rb +68 -0
  18. data/lib/scss_lint/lint.rb +24 -0
  19. data/lib/scss_lint/linter.rb +161 -0
  20. data/lib/scss_lint/linter/bang_format.rb +52 -0
  21. data/lib/scss_lint/linter/border_zero.rb +39 -0
  22. data/lib/scss_lint/linter/color_keyword.rb +32 -0
  23. data/lib/scss_lint/linter/color_variable.rb +60 -0
  24. data/lib/scss_lint/linter/comment.rb +21 -0
  25. data/lib/scss_lint/linter/compass.rb +7 -0
  26. data/lib/scss_lint/linter/compass/property_with_mixin.rb +47 -0
  27. data/lib/scss_lint/linter/debug_statement.rb +10 -0
  28. data/lib/scss_lint/linter/declaration_order.rb +71 -0
  29. data/lib/scss_lint/linter/duplicate_property.rb +58 -0
  30. data/lib/scss_lint/linter/else_placement.rb +48 -0
  31. data/lib/scss_lint/linter/empty_line_between_blocks.rb +85 -0
  32. data/lib/scss_lint/linter/empty_rule.rb +11 -0
  33. data/lib/scss_lint/linter/final_newline.rb +20 -0
  34. data/lib/scss_lint/linter/hex_length.rb +56 -0
  35. data/lib/scss_lint/linter/hex_notation.rb +38 -0
  36. data/lib/scss_lint/linter/hex_validation.rb +23 -0
  37. data/lib/scss_lint/linter/id_selector.rb +10 -0
  38. data/lib/scss_lint/linter/import_path.rb +62 -0
  39. data/lib/scss_lint/linter/important_rule.rb +12 -0
  40. data/lib/scss_lint/linter/indentation.rb +197 -0
  41. data/lib/scss_lint/linter/leading_zero.rb +49 -0
  42. data/lib/scss_lint/linter/mergeable_selector.rb +60 -0
  43. data/lib/scss_lint/linter/name_format.rb +117 -0
  44. data/lib/scss_lint/linter/nesting_depth.rb +24 -0
  45. data/lib/scss_lint/linter/placeholder_in_extend.rb +22 -0
  46. data/lib/scss_lint/linter/property_count.rb +44 -0
  47. data/lib/scss_lint/linter/property_sort_order.rb +198 -0
  48. data/lib/scss_lint/linter/property_spelling.rb +49 -0
  49. data/lib/scss_lint/linter/property_units.rb +59 -0
  50. data/lib/scss_lint/linter/qualifying_element.rb +42 -0
  51. data/lib/scss_lint/linter/selector_depth.rb +64 -0
  52. data/lib/scss_lint/linter/selector_format.rb +102 -0
  53. data/lib/scss_lint/linter/shorthand.rb +139 -0
  54. data/lib/scss_lint/linter/single_line_per_property.rb +59 -0
  55. data/lib/scss_lint/linter/single_line_per_selector.rb +35 -0
  56. data/lib/scss_lint/linter/space_after_comma.rb +110 -0
  57. data/lib/scss_lint/linter/space_after_property_colon.rb +92 -0
  58. data/lib/scss_lint/linter/space_after_property_name.rb +27 -0
  59. data/lib/scss_lint/linter/space_before_brace.rb +72 -0
  60. data/lib/scss_lint/linter/space_between_parens.rb +35 -0
  61. data/lib/scss_lint/linter/string_quotes.rb +94 -0
  62. data/lib/scss_lint/linter/trailing_semicolon.rb +67 -0
  63. data/lib/scss_lint/linter/trailing_zero.rb +41 -0
  64. data/lib/scss_lint/linter/unnecessary_mantissa.rb +42 -0
  65. data/lib/scss_lint/linter/unnecessary_parent_reference.rb +49 -0
  66. data/lib/scss_lint/linter/url_format.rb +56 -0
  67. data/lib/scss_lint/linter/url_quotes.rb +27 -0
  68. data/lib/scss_lint/linter/variable_for_property.rb +30 -0
  69. data/lib/scss_lint/linter/vendor_prefix.rb +64 -0
  70. data/lib/scss_lint/linter/zero_unit.rb +39 -0
  71. data/lib/scss_lint/linter_registry.rb +26 -0
  72. data/lib/scss_lint/location.rb +38 -0
  73. data/lib/scss_lint/options.rb +109 -0
  74. data/lib/scss_lint/rake_task.rb +106 -0
  75. data/lib/scss_lint/reporter.rb +18 -0
  76. data/lib/scss_lint/reporter/config_reporter.rb +26 -0
  77. data/lib/scss_lint/reporter/default_reporter.rb +27 -0
  78. data/lib/scss_lint/reporter/files_reporter.rb +8 -0
  79. data/lib/scss_lint/reporter/json_reporter.rb +30 -0
  80. data/lib/scss_lint/reporter/xml_reporter.rb +33 -0
  81. data/lib/scss_lint/runner.rb +51 -0
  82. data/lib/scss_lint/sass/script.rb +78 -0
  83. data/lib/scss_lint/sass/tree.rb +168 -0
  84. data/lib/scss_lint/selector_visitor.rb +34 -0
  85. data/lib/scss_lint/utils.rb +112 -0
  86. data/lib/scss_lint/version.rb +4 -0
  87. data/spec/scss_lint/cli_spec.rb +177 -0
  88. data/spec/scss_lint/config_spec.rb +253 -0
  89. data/spec/scss_lint/engine_spec.rb +24 -0
  90. data/spec/scss_lint/file_finder_spec.rb +134 -0
  91. data/spec/scss_lint/linter/bang_format_spec.rb +121 -0
  92. data/spec/scss_lint/linter/border_zero_spec.rb +118 -0
  93. data/spec/scss_lint/linter/color_keyword_spec.rb +83 -0
  94. data/spec/scss_lint/linter/color_variable_spec.rb +155 -0
  95. data/spec/scss_lint/linter/comment_spec.rb +79 -0
  96. data/spec/scss_lint/linter/compass/property_with_mixin_spec.rb +55 -0
  97. data/spec/scss_lint/linter/debug_statement_spec.rb +21 -0
  98. data/spec/scss_lint/linter/declaration_order_spec.rb +575 -0
  99. data/spec/scss_lint/linter/duplicate_property_spec.rb +189 -0
  100. data/spec/scss_lint/linter/else_placement_spec.rb +106 -0
  101. data/spec/scss_lint/linter/empty_line_between_blocks_spec.rb +276 -0
  102. data/spec/scss_lint/linter/empty_rule_spec.rb +27 -0
  103. data/spec/scss_lint/linter/final_newline_spec.rb +49 -0
  104. data/spec/scss_lint/linter/hex_length_spec.rb +104 -0
  105. data/spec/scss_lint/linter/hex_notation_spec.rb +104 -0
  106. data/spec/scss_lint/linter/hex_validation_spec.rb +40 -0
  107. data/spec/scss_lint/linter/id_selector_spec.rb +62 -0
  108. data/spec/scss_lint/linter/import_path_spec.rb +300 -0
  109. data/spec/scss_lint/linter/important_rule_spec.rb +43 -0
  110. data/spec/scss_lint/linter/indentation_spec.rb +347 -0
  111. data/spec/scss_lint/linter/leading_zero_spec.rb +233 -0
  112. data/spec/scss_lint/linter/mergeable_selector_spec.rb +283 -0
  113. data/spec/scss_lint/linter/name_format_spec.rb +282 -0
  114. data/spec/scss_lint/linter/nesting_depth_spec.rb +114 -0
  115. data/spec/scss_lint/linter/placeholder_in_extend_spec.rb +63 -0
  116. data/spec/scss_lint/linter/property_count_spec.rb +104 -0
  117. data/spec/scss_lint/linter/property_sort_order_spec.rb +482 -0
  118. data/spec/scss_lint/linter/property_spelling_spec.rb +84 -0
  119. data/spec/scss_lint/linter/property_units_spec.rb +229 -0
  120. data/spec/scss_lint/linter/qualifying_element_spec.rb +125 -0
  121. data/spec/scss_lint/linter/selector_depth_spec.rb +159 -0
  122. data/spec/scss_lint/linter/selector_format_spec.rb +632 -0
  123. data/spec/scss_lint/linter/shorthand_spec.rb +198 -0
  124. data/spec/scss_lint/linter/single_line_per_property_spec.rb +73 -0
  125. data/spec/scss_lint/linter/single_line_per_selector_spec.rb +130 -0
  126. data/spec/scss_lint/linter/space_after_comma_spec.rb +332 -0
  127. data/spec/scss_lint/linter/space_after_property_colon_spec.rb +373 -0
  128. data/spec/scss_lint/linter/space_after_property_name_spec.rb +37 -0
  129. data/spec/scss_lint/linter/space_before_brace_spec.rb +829 -0
  130. data/spec/scss_lint/linter/space_between_parens_spec.rb +263 -0
  131. data/spec/scss_lint/linter/string_quotes_spec.rb +335 -0
  132. data/spec/scss_lint/linter/trailing_semicolon_spec.rb +304 -0
  133. data/spec/scss_lint/linter/trailing_zero_spec.rb +176 -0
  134. data/spec/scss_lint/linter/unnecessary_mantissa_spec.rb +67 -0
  135. data/spec/scss_lint/linter/unnecessary_parent_reference_spec.rb +98 -0
  136. data/spec/scss_lint/linter/url_format_spec.rb +55 -0
  137. data/spec/scss_lint/linter/url_quotes_spec.rb +73 -0
  138. data/spec/scss_lint/linter/variable_for_property_spec.rb +145 -0
  139. data/spec/scss_lint/linter/vendor_prefix_spec.rb +371 -0
  140. data/spec/scss_lint/linter/zero_unit_spec.rb +113 -0
  141. data/spec/scss_lint/linter_registry_spec.rb +50 -0
  142. data/spec/scss_lint/linter_spec.rb +292 -0
  143. data/spec/scss_lint/location_spec.rb +42 -0
  144. data/spec/scss_lint/options_spec.rb +34 -0
  145. data/spec/scss_lint/rake_task_spec.rb +43 -0
  146. data/spec/scss_lint/reporter/config_reporter_spec.rb +42 -0
  147. data/spec/scss_lint/reporter/default_reporter_spec.rb +73 -0
  148. data/spec/scss_lint/reporter/files_reporter_spec.rb +38 -0
  149. data/spec/scss_lint/reporter/json_reporter_spec.rb +96 -0
  150. data/spec/scss_lint/reporter/xml_reporter_spec.rb +103 -0
  151. data/spec/scss_lint/reporter_spec.rb +11 -0
  152. data/spec/scss_lint/runner_spec.rb +123 -0
  153. data/spec/scss_lint/selector_visitor_spec.rb +264 -0
  154. data/spec/spec_helper.rb +34 -0
  155. data/spec/support/isolated_environment.rb +25 -0
  156. data/spec/support/matchers/report_lint.rb +48 -0
  157. metadata +328 -0
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe SCSSLint::Location do
4
+ let(:engine) { described_class.new(css) }
5
+
6
+ describe '#<=>' do
7
+ let(:locations) do
8
+ [
9
+ SCSSLint::Location.new(2, 2, 2),
10
+ SCSSLint::Location.new(2, 2, 1),
11
+ SCSSLint::Location.new(2, 1, 2),
12
+ SCSSLint::Location.new(2, 1, 1),
13
+ SCSSLint::Location.new(1, 2, 2),
14
+ SCSSLint::Location.new(1, 2, 1),
15
+ SCSSLint::Location.new(1, 1, 2),
16
+ SCSSLint::Location.new(1, 1, 1)
17
+ ]
18
+ end
19
+
20
+ it 'allows locations to be sorted' do
21
+ locations.sort.should == [
22
+ SCSSLint::Location.new(1, 1, 1),
23
+ SCSSLint::Location.new(1, 1, 2),
24
+ SCSSLint::Location.new(1, 2, 1),
25
+ SCSSLint::Location.new(1, 2, 2),
26
+ SCSSLint::Location.new(2, 1, 1),
27
+ SCSSLint::Location.new(2, 1, 2),
28
+ SCSSLint::Location.new(2, 2, 1),
29
+ SCSSLint::Location.new(2, 2, 2)
30
+ ]
31
+ end
32
+
33
+ context 'when the same location is passed' do
34
+ let(:location) { SCSSLint::Location.new(1, 1, 1) }
35
+ let(:other_location) { SCSSLint::Location.new(1, 1, 1) }
36
+
37
+ it 'returns 0' do
38
+ (location <=> other_location).should == 0
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+ require 'scss_lint/options'
3
+
4
+ describe SCSSLint::Options do
5
+ describe '#parse' do
6
+ subject { super().parse(args) }
7
+
8
+ context 'when no arguments are specified' do
9
+ let(:args) { [] }
10
+
11
+ it { should be_a Hash }
12
+
13
+ it 'defines no files to lint by default' do
14
+ subject[:files].should be_empty
15
+ end
16
+
17
+ it 'specifies the DefaultReporter by default' do
18
+ subject[:reporters].first.should include 'Default'
19
+ end
20
+
21
+ it 'outputs to STDOUT' do
22
+ subject[:reporters].first.should include :stdout
23
+ end
24
+ end
25
+
26
+ context 'when a non-existent flag is specified' do
27
+ let(:args) { ['--totally-made-up-flag'] }
28
+
29
+ it 'raises an error' do
30
+ expect { subject }.to raise_error SCSSLint::Exceptions::InvalidCLIOption
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ require 'scss_lint/rake_task'
3
+ require 'tempfile'
4
+
5
+ describe SCSSLint::RakeTask do
6
+ before(:all) do
7
+ SCSSLint::RakeTask.new
8
+ end
9
+
10
+ before do
11
+ STDOUT.stub(:write) # Silence console output
12
+ end
13
+
14
+ let(:file) do
15
+ Tempfile.new(%w[scss-file .scss]).tap do |f|
16
+ f.write(scss)
17
+ f.close
18
+ end
19
+ end
20
+
21
+ def run_task
22
+ Rake::Task[:scss_lint].tap do |t|
23
+ t.reenable # Allows us to execute task multiple times
24
+ t.invoke(file.path)
25
+ end
26
+ end
27
+
28
+ context 'when SCSS document is valid with no lints' do
29
+ let(:scss) { '' }
30
+
31
+ it 'does not call Kernel.exit' do
32
+ expect { run_task }.not_to raise_error
33
+ end
34
+ end
35
+
36
+ context 'when SCSS document is invalid' do
37
+ let(:scss) { '.class {' }
38
+
39
+ it 'calls Kernel.exit with the status code' do
40
+ expect { run_task }.to raise_error SystemExit
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe SCSSLint::Reporter::ConfigReporter do
4
+ subject { YAML.load(result) }
5
+ let(:result) { described_class.new(lints).report_lints }
6
+
7
+ describe '#report_lints' do
8
+ context 'when there are no lints' do
9
+ let(:lints) { [] }
10
+
11
+ it 'returns nil' do
12
+ result.should be_nil
13
+ end
14
+ end
15
+
16
+ context 'when there are lints' do
17
+ let(:linters) do
18
+ [SCSSLint::Linter::FinalNewline, SCSSLint::Linter::BorderZero,
19
+ SCSSLint::Linter::BorderZero, nil]
20
+ end
21
+ let(:lints) do
22
+ linters.each.map do |linter|
23
+ SCSSLint::Lint.new(linter ? linter.new : nil, '',
24
+ SCSSLint::Location.new, '')
25
+ end
26
+ end
27
+
28
+ it 'adds one entry per linter' do
29
+ subject['linters'].size.should eq 2
30
+ end
31
+
32
+ it 'sorts linters by name' do
33
+ subject['linters'].map(&:first).should eq %w[BorderZero FinalNewline]
34
+ end
35
+
36
+ it 'disables all found linters' do
37
+ subject['linters']['BorderZero']['enabled'].should eq false
38
+ subject['linters']['FinalNewline']['enabled'].should eq false
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe SCSSLint::Reporter::DefaultReporter do
4
+ subject { SCSSLint::Reporter::DefaultReporter.new(lints) }
5
+
6
+ describe '#report_lints' do
7
+ context 'when there are no lints' do
8
+ let(:lints) { [] }
9
+
10
+ it 'returns nil' do
11
+ subject.report_lints.should be_nil
12
+ end
13
+ end
14
+
15
+ context 'when there are lints' do
16
+ let(:filenames) { ['some-filename.scss', 'other-filename.scss'] }
17
+ let(:lines) { [502, 724] }
18
+ let(:descriptions) { ['Description of lint 1', 'Description of lint 2'] }
19
+ let(:severities) { [:warning] * 2 }
20
+ let(:lints) do
21
+ filenames.each_with_index.map do |filename, index|
22
+ location = SCSSLint::Location.new(lines[index])
23
+ SCSSLint::Lint.new(nil, filename, location, descriptions[index],
24
+ severities[index])
25
+ end
26
+ end
27
+
28
+ it 'prints each lint on its own line' do
29
+ subject.report_lints.count("\n").should == 2
30
+ end
31
+
32
+ it 'prints a trailing newline' do
33
+ subject.report_lints[-1].should == "\n"
34
+ end
35
+
36
+ it 'prints the filename for each lint' do
37
+ filenames.each do |filename|
38
+ subject.report_lints.scan(/#{filename}/).count.should == 1
39
+ end
40
+ end
41
+
42
+ it 'prints the line number for each lint' do
43
+ lines.each do |line|
44
+ subject.report_lints.scan(/#{line}/).count.should == 1
45
+ end
46
+ end
47
+
48
+ it 'prints the description for each lint' do
49
+ descriptions.each do |description|
50
+ subject.report_lints.scan(/#{description}/).count.should == 1
51
+ end
52
+ end
53
+
54
+ context 'when lints are warnings' do
55
+ it 'prints the warning severity code on each line' do
56
+ subject.report_lints.split("\n").each do |line|
57
+ line.scan(/\[W\]/).count.should == 1
58
+ end
59
+ end
60
+ end
61
+
62
+ context 'when lints are errors' do
63
+ let(:severities) { [:error] * 2 }
64
+
65
+ it 'prints the error severity code on each line' do
66
+ subject.report_lints.split("\n").each do |line|
67
+ line.scan(/\[E\]/).count.should == 1
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe SCSSLint::Reporter::FilesReporter do
4
+ subject { described_class.new(lints) }
5
+
6
+ describe '#report_lints' do
7
+ context 'when there are no lints' do
8
+ let(:lints) { [] }
9
+
10
+ it 'returns nil' do
11
+ subject.report_lints.should be_nil
12
+ end
13
+ end
14
+
15
+ context 'when there are lints' do
16
+ let(:filenames) { ['some-filename.scss', 'some-filename.scss', 'other-filename.scss'] }
17
+ let(:lints) do
18
+ filenames.map do |filename|
19
+ SCSSLint::Lint.new(nil, filename, SCSSLint::Location.new, '')
20
+ end
21
+ end
22
+
23
+ it 'prints each file on its own line' do
24
+ subject.report_lints.count("\n").should == 2
25
+ end
26
+
27
+ it 'prints a trailing newline' do
28
+ subject.report_lints[-1].should == "\n"
29
+ end
30
+
31
+ it 'prints the filename for each lint' do
32
+ filenames.each do |filename|
33
+ subject.report_lints.scan(/#{filename}/).count.should == 1
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+
3
+ describe SCSSLint::Reporter::JSONReporter do
4
+ subject { SCSSLint::Reporter::JSONReporter.new(lints) }
5
+
6
+ describe '#report_lints' do
7
+ let(:json) { JSON.parse(subject.report_lints) }
8
+
9
+ shared_examples_for 'parsed JSON' do
10
+ it 'is a Hash' do
11
+ json.is_a?(Hash)
12
+ end
13
+ end
14
+
15
+ context 'when there are no lints' do
16
+ let(:lints) { [] }
17
+
18
+ it_should_behave_like 'parsed JSON'
19
+ end
20
+
21
+ context 'when there are lints' do
22
+ let(:filenames) { ['f1.scss', 'f2.scss', 'f1.scss'] }
23
+ # Include invalid XML characters in the third description to validate
24
+ # that escaping happens for preventing broken XML output
25
+ let(:descriptions) { ['lint 1', 'lint 2', 'lint 3 " \' < & >'] }
26
+ let(:severities) { [:warning] * 3 }
27
+
28
+ let(:locations) do
29
+ [
30
+ SCSSLint::Location.new(5, 2, 3),
31
+ SCSSLint::Location.new(7, 6, 2),
32
+ SCSSLint::Location.new(9, 10, 1)
33
+ ]
34
+ end
35
+
36
+ let(:lints) do
37
+ filenames.each_with_index.map do |filename, index|
38
+ SCSSLint::Lint.new(nil, filename, locations[index],
39
+ descriptions[index], severities[index])
40
+ end
41
+ end
42
+
43
+ it_should_behave_like 'parsed JSON'
44
+
45
+ it 'contains an <issue> node for each lint' do
46
+ json.values.inject(0) { |sum, issues| sum + issues.size }.should == 3
47
+ end
48
+
49
+ it 'contains a group of issues for each file' do
50
+ json.keys.should == filenames.uniq
51
+ end
52
+
53
+ it 'contains <issue> nodes grouped by <file>' do
54
+ json.values.map(&:size).should == [2, 1]
55
+ end
56
+
57
+ it 'marks each issue with a line number' do
58
+ json.values.flat_map { |issues| issues.map { |issue| issue['line'] } }
59
+ .should =~ locations.map(&:line)
60
+ end
61
+
62
+ it 'marks each issue with a column number' do
63
+ json.values.flat_map { |issues| issues.map { |issue| issue['column'] } }
64
+ .should =~ locations.map(&:column)
65
+ end
66
+
67
+ it 'marks each issue with a length' do
68
+ json.values.flat_map { |issues| issues.map { |issue| issue['length'] } }
69
+ .should =~ locations.map(&:length)
70
+ end
71
+
72
+ it 'marks each issue with a reason containing the lint description' do
73
+ json.values.flat_map { |issues| issues.map { |issue| issue['reason'] } }
74
+ .should =~ descriptions
75
+ end
76
+
77
+ context 'when lints are warnings' do
78
+ it 'marks each issue with a severity of "warning"' do
79
+ json.values.inject(0) do |sum, issues|
80
+ sum + issues.select { |i| i['severity'] == 'warning' }.size
81
+ end.should == 3
82
+ end
83
+ end
84
+
85
+ context 'when lints are errors' do
86
+ let(:severities) { [:error] * 3 }
87
+
88
+ it 'marks each issue with a severity of "error"' do
89
+ json.values.inject(0) do |sum, issues|
90
+ sum + issues.select { |i| i['severity'] == 'error' }.size
91
+ end.should == 3
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+
3
+ describe SCSSLint::Reporter::XMLReporter do
4
+ subject { SCSSLint::Reporter::XMLReporter.new(lints) }
5
+
6
+ describe '#report_lints' do
7
+ let(:xml) { Nokogiri::XML(subject.report_lints) }
8
+
9
+ shared_examples_for 'XML document' do
10
+ it 'has an encoding of UTF-8' do
11
+ xml.encoding.should == 'utf-8'
12
+ end
13
+
14
+ it 'has an XML version of 1.0' do
15
+ xml.version.should == '1.0'
16
+ end
17
+
18
+ it 'contains a <lint> root element' do
19
+ xml.root.name.should == 'lint'
20
+ end
21
+ end
22
+
23
+ context 'when there are no lints' do
24
+ let(:lints) { [] }
25
+
26
+ it_should_behave_like 'XML document'
27
+ end
28
+
29
+ context 'when there are lints' do
30
+ let(:filenames) { ['f1.scss', 'f2.scss', 'f1.scss'] }
31
+ # Include invalid XML characters in the third description to validate
32
+ # that escaping happens for preventing broken XML output
33
+ let(:descriptions) { ['lint 1', 'lint 2', 'lint 3 " \' < & >'] }
34
+ let(:severities) { [:warning] * 3 }
35
+
36
+ let(:locations) do
37
+ [
38
+ SCSSLint::Location.new(5, 2, 3),
39
+ SCSSLint::Location.new(7, 6, 2),
40
+ SCSSLint::Location.new(9, 10, 1)
41
+ ]
42
+ end
43
+
44
+ let(:lints) do
45
+ filenames.each_with_index.map do |filename, index|
46
+ SCSSLint::Lint.new(nil, filename, locations[index],
47
+ descriptions[index], severities[index])
48
+ end
49
+ end
50
+
51
+ it_should_behave_like 'XML document'
52
+
53
+ it 'contains an <issue> node for each lint' do
54
+ xml.xpath('//issue').count.should == 3
55
+ end
56
+
57
+ it 'contains a <file> node for each file' do
58
+ xml.xpath('//file').map { |node| node[:name] }
59
+ .should =~ filenames.uniq
60
+ end
61
+
62
+ it 'contains <issue> nodes grouped by <file>' do
63
+ xml.xpath('//file').map do |file_node|
64
+ file_node.xpath('./issue').count
65
+ end.should =~ [1, 2]
66
+ end
67
+
68
+ it 'marks each issue with a line number' do
69
+ xml.xpath('//issue[@line]').map { |node| node[:line] }
70
+ .should =~ locations.map { |location| location.line.to_s }
71
+ end
72
+
73
+ it 'marks each issue with a column number' do
74
+ xml.xpath('//issue[@column]').map { |node| node[:column] }
75
+ .should =~ locations.map { |location| location.column.to_s }
76
+ end
77
+
78
+ it 'marks each issue with a length' do
79
+ xml.xpath('//issue[@length]').map { |node| node[:length] }
80
+ .should =~ locations.map { |location| location.length.to_s }
81
+ end
82
+
83
+ it 'marks each issue with a reason containing the lint description' do
84
+ xml.xpath('//issue[@reason]').map { |node| node[:reason] }
85
+ .should =~ descriptions
86
+ end
87
+
88
+ context 'when lints are warnings' do
89
+ it 'marks each issue with a severity of "warning"' do
90
+ xml.xpath("//issue[@severity='warning']").count == 3
91
+ end
92
+ end
93
+
94
+ context 'when lints are errors' do
95
+ let(:severities) { [:error] * 3 }
96
+
97
+ it 'marks each issue with a severity of "error"' do
98
+ xml.xpath("//issue[@severity='error']").count == 3
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end