Skip to content

Commit 84eca55

Browse files
committed
Merge pull request #692 from mgreter/feature/spec-runner-improve
Improve spec test runner
2 parents 27e7d2e + 9eeaf95 commit 84eca55

File tree

179 files changed

+392
-338
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

179 files changed

+392
-338
lines changed

lib/sass_spec/engine_adapter.rb

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
require "open3"
2-
31
class EngineAdapter
42
def describe
53
not_implemented
@@ -39,13 +37,15 @@ def describe
3937
end
4038

4139
def version
42-
stdout, stderr, status = Open3.capture3("#{@command} -v")
40+
require 'open3'
41+
stdout, stderr, status = Open3.capture3("#{@command} -v", :binmode => true)
4342
stdout.to_s
4443
end
4544

4645

4746
def compile(sass_filename, style)
48-
stdout, stderr, status = Open3.capture3("#{@command} -t #{style} #{sass_filename}")
47+
require 'open3'
48+
stdout, stderr, status = Open3.capture3("#{@command} -t #{style} #{sass_filename}", :binmode => true)
4949
[stdout, stderr, status.exitstatus]
5050
end
5151
end
@@ -66,20 +66,34 @@ def version
6666

6767
def compile(sass_filename, style)
6868
require 'sass'
69+
# overloads STDERR
70+
stderr = StringIO.new
71+
# restore previous default encoding
72+
encoding = Encoding.default_external
73+
# Does not work as expected when tests are run in parallel
74+
# It runs tests in threads, so stderr is shared across them
75+
old_stderr, $stderr = $stderr, stderr
6976
begin
70-
captured_stderr = StringIO.new
71-
# Does not work as expected when tests are run in parallel
72-
real_stderr, $stderr = $stderr, captured_stderr
73-
begin
74-
css_output = Sass.compile_file(sass_filename.to_s, :style => style.to_sym)
75-
[css_output, captured_stderr.string, 0]
76-
rescue Sass::SyntaxError => e
77-
["", "Error: " + e.message.to_s, 1]
78-
rescue => e
79-
["", e.to_s, 2]
80-
end
81-
ensure
82-
$stderr = real_stderr
77+
Encoding.default_external = "UTF-8"
78+
css_output = Sass.compile_file(sass_filename.to_s, :style => style.to_sym)
79+
# strings come back as utf8 encoded
80+
# internaly we only work with bytes
81+
err_output = stderr.string
82+
err_output.force_encoding('ASCII-8BIT')
83+
css_output.force_encoding('ASCII-8BIT')
84+
[css_output, err_output, 0]
85+
rescue Sass::SyntaxError => e
86+
# prepend the prefix to the message
87+
# and indent all lines to match it
88+
err_output = "Error: " + e.message.to_s
89+
.gsub(/(?:\r?\n)(?!\z)/, "\n ")
90+
err_output.force_encoding('ASCII-8BIT')
91+
["", err_output, 65]
92+
rescue => e
93+
["", e.to_s, 2]
8394
end
95+
ensure
96+
$stderr = old_stderr
97+
Encoding.default_external = encoding
8498
end
8599
end

lib/sass_spec/test.rb

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,24 @@ def run_spec_test(test_case, options = {})
1111

1212
if test_case.overwrite?
1313
if status != 0
14-
File.open(test_case.status_path, "w+") do |f|
14+
File.open(test_case.status_path, "w+", :binmode => true) do |f|
1515
f.write(status)
1616
f.close
1717
end
18+
elsif (File.file?(test_case.status_path))
19+
File.unlink(test_case.status_path)
1820
end
1921

2022
if error.length > 0
21-
File.open(test_case.error_path, "w+") do |f|
23+
File.open(test_case.error_path, "w+", :binmode => true) do |f|
2224
f.write(error)
2325
f.close
2426
end
27+
elsif (File.file?(test_case.error_path))
28+
File.unlink(test_case.error_path)
2529
end
2630

27-
File.open(test_case.expected_path, "w+") do |f|
31+
File.open(test_case.expected_path, "w+", :binmode => true) do |f|
2832
f.write(output)
2933
f.close
3034
end
@@ -43,15 +47,74 @@ def run_spec_test(test_case, options = {})
4347
if test_case.verify_stderr?
4448
# Compare only first line of error output (we can't compare stacktraces etc.)
4549
begin
50+
skip = false
4651
error_lines = error.each_line
47-
error_msg = error_lines.next.rstrip
48-
if (error_msg =~ /DEPRECATION WARNING:? on line/)
49-
error_msg = error_lines.next.rstrip
52+
while error_line = error_lines.next do
53+
if (error_line =~ /DEPRECATION WARNING/)
54+
skip = false
55+
end
56+
if (error_line =~ /Error:/)
57+
skip = false
58+
end
59+
# disable once we support this deprecation fully
60+
if (error_line =~ /interpolation near operators will be simplified/)
61+
skip = true
62+
next
63+
end
64+
# disable once we support this deprecation fully
65+
# if (error_line =~ /The subject selector operator \"!\" is deprecated and will be removed/)
66+
# skip = true
67+
# next
68+
# end
69+
# disable once we support this deprecation fully
70+
if (error_line =~ /Passing a percentage as the alpha/)
71+
skip = true
72+
next
73+
end
74+
# disable once we support this deprecation fully (partial now)
75+
# if (error_line =~ /, a non-string value, to unquote()/)
76+
# skip = true
77+
# next
78+
# end
79+
if (skip)
80+
next
81+
end
82+
error_msg = error_line.rstrip
83+
break
5084
end
5185
expected_error_lines = test_case.expected_error.each_line
52-
expected_error_msg = expected_error_lines.next.rstrip
53-
if (expected_error_msg =~ /DEPRECATION WARNING:? on line/)
54-
expected_error_msg = expected_error_lines.next.rstrip
86+
while expected_error_line = expected_error_lines.next do
87+
if (expected_error_line =~ /DEPRECATION WARNING/)
88+
skip = false
89+
end
90+
if (expected_error_line =~ /Error:/)
91+
skip = false
92+
end
93+
# disable once we support this deprecation fully
94+
if (expected_error_line =~ /interpolation near operators will be simplified/)
95+
skip = true
96+
next
97+
end
98+
# disable once we support this deprecation fully
99+
# if (expected_error_line =~ /The subject selector operator \"!\" is deprecated and will be removed/)
100+
# skip = true
101+
# next
102+
# end
103+
# disable once we support this deprecation fully
104+
if (expected_error_line =~ /Passing a percentage as the alpha/)
105+
skip = true
106+
next
107+
end
108+
# disable once we support this deprecation fully (partial now)
109+
# if (expected_error_line =~ /, a non-string value, to unquote()/)
110+
# skip = true
111+
# next
112+
# end
113+
if (skip)
114+
next
115+
end
116+
expected_error_msg = expected_error_line.rstrip
117+
break
55118
end
56119
error_msg = _clean_debug_path(error_msg)
57120
expected_error_msg = _clean_debug_path(expected_error_msg)
@@ -79,12 +142,12 @@ def _clean_debug_path(error)
79142
pwd = Dir.pwd
80143
url = pwd.gsub(/\\/, '\/')
81144
error.gsub(/^.*?(input.scss:\d+ DEBUG:)/, '\1')
82-
.gsub(/[ ]+/, " ")
145+
.gsub(/\/+/, "/")
83146
.gsub(/#{Regexp.quote(url)}\//, "/sass/sass-spec/")
84147
.gsub(/#{Regexp.quote(pwd)}\//, "/sass/sass-spec/")
85148
.gsub(/(?:\/todo_|_todo\/)/, "/")
86-
.gsub(/\/libsass\-[a-z]+\-test\//, "/")
87-
.gsub(/\/libsass\-[a-z]+\-issue/, "/libsass-issue")
149+
.gsub(/\/libsass\-[a-z]+\-tests\//, "/")
150+
.gsub(/\/libsass\-[a-z]+\-issues/, "/libsass-issues")
88151
.strip
89152
end
90153

lib/sass_spec/test_case.rb

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,24 @@ def output
6767
stdout, stderr, status = engine.compile(@input_path, @output_style)
6868

6969
if @clean_test
70-
cleaned = _clean_output(stdout)
70+
clean_out = _clean_output(stdout)
7171
else
72-
cleaned = _norm_output(stdout)
72+
clean_out = _norm_output(stdout)
7373
end
74-
@output ||= [stdout, cleaned, stderr, status]
74+
75+
stderr = _clean_error(stderr)
76+
# always replace windows linefeeds
77+
stdout = stdout.gsub(/(\r\n)/, "\n")
78+
stderr = stderr.gsub(/(\r\n)/, "\n")
79+
80+
@output ||= [stdout, clean_out, stderr, status]
7581
end
7682

7783
def expected
78-
output = File.read(@expected_path, :encoding => "utf-8")
84+
output = File.read(@expected_path, :binmode => true)
85+
# we seem to get CP850 otherwise
86+
# this provokes equal test to fail
87+
output.force_encoding('ASCII-8BIT')
7988
if @clean_test
8089
@expected ||= _clean_output(output)
8190
else
@@ -84,12 +93,12 @@ def expected
8493
end
8594

8695
def expected_error
87-
@expected_error = _clean_error(File.read(@error_path, :encoding => "utf-8"))
96+
@expected_error = _clean_error(File.read(@error_path, :binmode => true))
8897
end
8998

9099
def expected_status
91100
if should_fail?
92-
@expected_status = File.read(@status_path, :encoding => "utf-8").to_i
101+
@expected_status = File.read(@status_path).to_i
93102
else
94103
@expected_status = 0
95104
end
@@ -99,35 +108,39 @@ def engine
99108
@options[:engine_adapter]
100109
end
101110

111+
# normalization happens for every test
102112
def _norm_output(css)
103-
css = css.force_encoding('iso-8859-1').encode('utf-8')
104-
css.gsub(/(?:\r?\n)+/, "\n")
105-
.strip
113+
# we dont want to test for linux or windows line-feeds
114+
# but make sure we do not remove single cariage returns
115+
css = css.gsub(/(?:\r?\n)+/, "\n")
116+
end
117+
def _norm_error(err)
118+
# we dont want to test for linux or windows line-feeds
119+
# but make sure we do not remove single cariage returns
120+
err = err.gsub(/(?:\r?\n)+/, "\n")
121+
# remove all newlines at the end of the file
122+
err = err.sub(/(?:\r?\n)+\z/, "")
106123
end
107124

125+
# cleaning only happens when requested for test
126+
# done by creating `expected.type.clean` flag file
108127
def _clean_output(css)
109-
css = css.force_encoding('iso-8859-1').encode('utf-8')
110-
css.gsub(/\s+/, " ")
111-
.gsub(/ *\{/, " {\n")
128+
css.gsub(/ *\{/, " {\n")
112129
.gsub(/([;,]) */, "\\1\n")
113130
.gsub(/ *\} */, " }\n")
114131
.gsub(/;(?:\s*;)+/m, ";")
115132
.gsub(/;\r?\n }/m, " }")
133+
.gsub(/\r?\n/, "\n")
134+
.sub(/(?:\r?\n)+\z/, "")
116135
.strip
117136
end
118-
119137
def _clean_error(err)
120-
pwd = Dir.pwd
121-
url = pwd.gsub(/\\/, '/')
122-
err = err.force_encoding('iso-8859-1').encode('utf-8')
123-
err.gsub(/^.*?(input.scss:\d+ DEBUG:)/, '\1')
124-
.gsub(/[ ]+/, " ")
125-
.gsub(/#{Regexp.quote(url)}\//, "/sass/sass-spec/")
126-
.gsub(/#{Regexp.quote(pwd)}\//, "/sass/sass-spec/")
127-
.gsub(/(?:\/todo_|_todo\/)/, "/")
128-
.gsub(/\/libsass\-[a-z]+\-test\//, "/")
129-
.gsub(/\/libsass\-[a-z]+\-issue/, "/libsass-issue")
130-
.strip
138+
err.gsub(/(?:\/todo_|_todo\/)/, "/") # hide todo pre/suffix
139+
.gsub(/\/libsass\-[a-z]+\-tests\//, "/") # hide test directory
140+
.gsub(/\/libsass\-[a-z]+\-issues\//, "/libsass-issues/") # normalize issue specs
141+
.gsub(/[\w\/\-\\:]+?[\/\\]spec[\/\\]+/, "/sass/spec/") # normalize abs paths
142+
.sub(/(?:\r?\n)*\z/, "\n") # make sure we have exactly one trailing linefeed
143+
.sub(/\A(?:\r?[\n\s])+\z/, "") # clear the whole file if only whitespace
131144
end
132145

133146
end

spec/colors/basic/error

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
DEPRECATION WARNING: Passing red, a non-string value, to unquote()
22
will be an error in future versions of Sass.
3-
on line 8 of /sass/sass-spec/spec/colors/basic/input.scss
3+
on line 8 of /sass/spec/colors/basic/input.scss
44
DEPRECATION WARNING: Passing 0xf00, a non-string value, to unquote()
55
will be an error in future versions of Sass.
6-
on line 9 of /sass/sass-spec/spec/colors/basic/input.scss
6+
on line 9 of /sass/spec/colors/basic/input.scss
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Error: ".baz" failed to @extend "%foo".
22
The selector "%foo" was not found.
33
Use "@extend %foo !optional" if the extend should be able to fail.
4-
on line 2 of /sass/sass-spec/spec/errors/extend/placeholder/missing/input.scss
4+
on line 2 of /sass/spec/errors/extend/placeholder/missing/input.scss
55
Use --trace for backtrace.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Error: ".baz" failed to @extend ".foo".
22
The selector ".foo" was not found.
33
Use "@extend .foo !optional" if the extend should be able to fail.
4-
on line 2 of /sass/sass-spec/spec/errors/extend/selector/missing/input.scss
4+
on line 2 of /sass/spec/errors/extend/selector/missing/input.scss
55
Use --trace for backtrace.

spec/errors/fn-debug/property/error

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
Error: Illegal nesting: Only properties may be nested beneath properties.
2-
on line 3 of /sass/sass-spec/spec/errors/fn-debug/property/input.scss
2+
on line 3 of /sass/spec/errors/fn-debug/property/input.scss
33
Use --trace for backtrace.

spec/errors/fn-debug/ruleset/error

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
/sass/sass-spec/spec/errors/fn-debug/ruleset/input.scss:2 DEBUG: debug
1+
/sass/spec/errors/fn-debug/ruleset/input.scss:2 DEBUG: debug

spec/errors/fn-debug/simple/error

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
/sass/sass-spec/spec/errors/fn-debug/simple/input.scss:1 DEBUG: debug
1+
/sass/spec/errors/fn-debug/simple/input.scss:1 DEBUG: debug

spec/errors/fn-error/property/error

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
Error: Illegal nesting: Only properties may be nested beneath properties.
2-
on line 3 of /sass/sass-spec/spec/errors/fn-error/property/input.scss
2+
on line 3 of /sass/spec/errors/fn-error/property/input.scss
33
Use --trace for backtrace.

0 commit comments

Comments
 (0)