mirror of
https://github.com/haml/haml.git
synced 2022-11-09 12:33:31 -05:00
417 lines
12 KiB
Ruby
Executable file
417 lines
12 KiB
Ruby
Executable file
#!/usr/bin/env ruby
|
|
require File.dirname(__FILE__) + '/../test_helper'
|
|
require 'sass/plugin'
|
|
require 'fileutils'
|
|
|
|
class SassPluginTest < Test::Unit::TestCase
|
|
@@templates = %w{
|
|
complex script parent_ref import scss_import alt
|
|
subdir/subdir subdir/nested_subdir/nested_subdir
|
|
options
|
|
}
|
|
|
|
def setup
|
|
FileUtils.mkdir tempfile_loc
|
|
FileUtils.mkdir tempfile_loc(nil,"more_")
|
|
set_plugin_opts
|
|
Sass::Plugin.update_stylesheets
|
|
reset_mtimes
|
|
end
|
|
|
|
def teardown
|
|
clean_up_sassc
|
|
clear_callbacks
|
|
FileUtils.rm_r tempfile_loc
|
|
FileUtils.rm_r tempfile_loc(nil,"more_")
|
|
end
|
|
|
|
@@templates.each do |name|
|
|
define_method("test_template_renders_correctly (#{name})") do
|
|
assert_renders_correctly(name)
|
|
end
|
|
end
|
|
|
|
def test_no_update
|
|
File.delete(tempfile_loc('basic'))
|
|
assert_needs_update 'basic'
|
|
Sass::Plugin.update_stylesheets
|
|
assert_stylesheet_updated 'basic'
|
|
end
|
|
|
|
def test_update_needed_when_modified
|
|
touch 'basic'
|
|
assert_needs_update 'basic'
|
|
Sass::Plugin.update_stylesheets
|
|
assert_stylesheet_updated 'basic'
|
|
end
|
|
|
|
def test_update_needed_when_dependency_modified
|
|
touch 'basic'
|
|
assert_needs_update 'import'
|
|
Sass::Plugin.update_stylesheets
|
|
assert_stylesheet_updated 'basic'
|
|
assert_stylesheet_updated 'import'
|
|
end
|
|
|
|
def test_update_needed_when_scss_dependency_modified
|
|
touch 'scss_importee'
|
|
assert_needs_update 'import'
|
|
Sass::Plugin.update_stylesheets
|
|
assert_stylesheet_updated 'scss_importee'
|
|
assert_stylesheet_updated 'import'
|
|
end
|
|
|
|
def test_scss_update_needed_when_dependency_modified
|
|
touch 'basic'
|
|
assert_needs_update 'scss_import'
|
|
Sass::Plugin.update_stylesheets
|
|
assert_stylesheet_updated 'basic'
|
|
assert_stylesheet_updated 'scss_import'
|
|
end
|
|
|
|
def test_full_exception_handling
|
|
File.delete(tempfile_loc('bork1'))
|
|
Sass::Plugin.update_stylesheets
|
|
File.open(tempfile_loc('bork1')) do |file|
|
|
assert_equal(<<CSS.strip, file.read.split("\n")[0...6].join("\n"))
|
|
/*
|
|
Syntax error: Undefined variable: "$bork".
|
|
on line 2 of #{template_loc('bork1')}
|
|
|
|
1: bork
|
|
2: :bork $bork
|
|
CSS
|
|
end
|
|
File.delete(tempfile_loc('bork1'))
|
|
end
|
|
|
|
def test_nonfull_exception_handling
|
|
old_full_exception = Sass::Plugin.options[:full_exception]
|
|
Sass::Plugin.options[:full_exception] = false
|
|
|
|
File.delete(tempfile_loc('bork1'))
|
|
assert_raise(Sass::SyntaxError) {Sass::Plugin.update_stylesheets}
|
|
ensure
|
|
Sass::Plugin.options[:full_exception] = old_full_exception
|
|
end
|
|
|
|
def test_two_template_directories
|
|
set_plugin_opts :template_location => {
|
|
template_loc => tempfile_loc,
|
|
template_loc(nil,'more_') => tempfile_loc(nil,'more_')
|
|
}
|
|
Sass::Plugin.update_stylesheets
|
|
['more1', 'more_import'].each { |name| assert_renders_correctly(name, :prefix => 'more_') }
|
|
end
|
|
|
|
def test_two_template_directories_with_line_annotations
|
|
set_plugin_opts :line_comments => true,
|
|
:style => :nested,
|
|
:template_location => {
|
|
template_loc => tempfile_loc,
|
|
template_loc(nil,'more_') => tempfile_loc(nil,'more_')
|
|
}
|
|
Sass::Plugin.update_stylesheets
|
|
assert_renders_correctly('more1_with_line_comments', 'more1', :prefix => 'more_')
|
|
end
|
|
|
|
def test_merb_update
|
|
begin
|
|
require 'merb'
|
|
rescue LoadError
|
|
puts "\nmerb couldn't be loaded, skipping a test"
|
|
return
|
|
end
|
|
|
|
require 'sass/plugin/merb'
|
|
if defined?(MerbHandler)
|
|
MerbHandler.send(:define_method, :process_without_sass) { |*args| }
|
|
else
|
|
Merb::Rack::Application.send(:define_method, :call_without_sass) { |*args| }
|
|
end
|
|
|
|
set_plugin_opts
|
|
|
|
File.delete(tempfile_loc('basic'))
|
|
assert_needs_update 'basic'
|
|
|
|
if defined?(MerbHandler)
|
|
MerbHandler.new('.').process nil, nil
|
|
else
|
|
Merb::Rack::Application.new.call(::Rack::MockRequest.env_for('/'))
|
|
end
|
|
|
|
assert_stylesheet_updated 'basic'
|
|
end
|
|
|
|
def test_doesnt_render_partials
|
|
assert !File.exists?(tempfile_loc('_partial'))
|
|
end
|
|
|
|
# Callbacks
|
|
|
|
def test_updating_stylesheets_callback
|
|
# Should run even when there's nothing to update
|
|
assert_callback :updating_stylesheets, []
|
|
end
|
|
|
|
def test_updating_stylesheets_callback_with_individual_files
|
|
files = [[template_loc("basic"), tempfile_loc("basic")]]
|
|
assert_callback(:updating_stylesheets, files) {Sass::Plugin.update_stylesheets(files)}
|
|
end
|
|
|
|
def test_updating_stylesheets_callback_with_never_update
|
|
Sass::Plugin.options[:never_update] = true
|
|
assert_no_callback :updating_stylesheets
|
|
end
|
|
|
|
def test_updating_stylesheet_callback_for_updated_template
|
|
Sass::Plugin.options[:always_update] = false
|
|
touch 'basic'
|
|
assert_no_callback :updating_stylesheet, template_loc("complex"), tempfile_loc("complex") do
|
|
assert_callbacks(
|
|
[:updating_stylesheet, template_loc("basic"), tempfile_loc("basic")],
|
|
[:updating_stylesheet, template_loc("import"), tempfile_loc("import")])
|
|
end
|
|
end
|
|
|
|
def test_updating_stylesheet_callback_for_fresh_template
|
|
Sass::Plugin.options[:always_update] = false
|
|
assert_no_callback :updating_stylesheet
|
|
end
|
|
|
|
def test_updating_stylesheet_callback_for_error_template
|
|
Sass::Plugin.options[:always_update] = false
|
|
touch 'bork1'
|
|
assert_no_callback :updating_stylesheet
|
|
end
|
|
|
|
def test_not_updating_stylesheet_callback_for_fresh_template
|
|
Sass::Plugin.options[:always_update] = false
|
|
assert_callback :not_updating_stylesheet, template_loc("basic"), tempfile_loc("basic")
|
|
end
|
|
|
|
def test_not_updating_stylesheet_callback_for_updated_template
|
|
Sass::Plugin.options[:always_update] = false
|
|
assert_callback :not_updating_stylesheet, template_loc("complex"), tempfile_loc("complex") do
|
|
assert_no_callbacks(
|
|
[:updating_stylesheet, template_loc("basic"), tempfile_loc("basic")],
|
|
[:updating_stylesheet, template_loc("import"), tempfile_loc("import")])
|
|
end
|
|
end
|
|
|
|
def test_not_updating_stylesheet_callback_with_never_update
|
|
Sass::Plugin.options[:never_update] = true
|
|
assert_no_callback :not_updating_stylesheet
|
|
end
|
|
|
|
def test_not_updating_stylesheet_callback_for_partial
|
|
Sass::Plugin.options[:always_update] = false
|
|
assert_no_callback :not_updating_stylesheet, template_loc("_partial"), tempfile_loc("_partial")
|
|
end
|
|
|
|
def test_not_updating_stylesheet_callback_for_error
|
|
Sass::Plugin.options[:always_update] = false
|
|
touch 'bork1'
|
|
assert_no_callback :not_updating_stylesheet, template_loc("bork1"), tempfile_loc("bork1")
|
|
end
|
|
|
|
def test_compilation_error_callback
|
|
Sass::Plugin.options[:always_update] = false
|
|
touch 'bork1'
|
|
assert_callback(:compilation_error,
|
|
lambda {|e| e.message == 'Undefined variable: "$bork".'},
|
|
template_loc("bork1"), tempfile_loc("bork1"))
|
|
end
|
|
|
|
def test_compilation_error_callback_for_file_access
|
|
Sass::Plugin.options[:always_update] = false
|
|
assert_callback(:compilation_error,
|
|
lambda {|e| e.is_a?(Errno::ENOENT)},
|
|
template_loc("nonexistent"), tempfile_loc("nonexistent")) do
|
|
Sass::Plugin.update_stylesheets([[template_loc("nonexistent"), tempfile_loc("nonexistent")]])
|
|
end
|
|
end
|
|
|
|
def test_creating_directory_callback
|
|
Sass::Plugin.options[:always_update] = false
|
|
dir = File.join(tempfile_loc, "subdir", "nested_subdir")
|
|
FileUtils.rm_r dir
|
|
assert_callback :creating_directory, dir
|
|
end
|
|
|
|
## Regression
|
|
|
|
def test_cached_dependencies_update
|
|
FileUtils.mv(template_loc("basic"), template_loc("basic", "more_"))
|
|
set_plugin_opts :load_paths => [result_loc, template_loc(nil, "more_")]
|
|
|
|
touch 'basic', 'more_'
|
|
assert_needs_update "import"
|
|
Sass::Plugin.update_stylesheets
|
|
assert_renders_correctly("import")
|
|
ensure
|
|
FileUtils.mv(template_loc("basic", "more_"), template_loc("basic"))
|
|
end
|
|
|
|
private
|
|
|
|
def assert_renders_correctly(*arguments)
|
|
options = arguments.last.is_a?(Hash) ? arguments.pop : {}
|
|
prefix = options[:prefix]
|
|
result_name = arguments.shift
|
|
tempfile_name = arguments.shift || result_name
|
|
expected_lines = File.read(result_loc(result_name, prefix)).split("\n")
|
|
actual_lines = File.read(tempfile_loc(tempfile_name, prefix)).split("\n")
|
|
|
|
if actual_lines.first == "/*" && expected_lines.first != "/*"
|
|
assert(false, actual_lines[0..actual_lines.enum_with_index.find {|l, i| l == "*/"}.last].join("\n"))
|
|
end
|
|
|
|
expected_lines.zip(actual_lines).each_with_index do |pair, line|
|
|
message = "template: #{result_name}\nline: #{line + 1}"
|
|
assert_equal(pair.first, pair.last, message)
|
|
end
|
|
if expected_lines.size < actual_lines.size
|
|
assert(false, "#{actual_lines.size - expected_lines.size} Trailing lines found in #{tempfile_name}.css: #{actual_lines[expected_lines.size..-1].join('\n')}")
|
|
end
|
|
end
|
|
|
|
def assert_stylesheet_updated(name)
|
|
assert_doesnt_need_update name
|
|
|
|
# Make sure it isn't an exception
|
|
expected_lines = File.read(result_loc(name)).split("\n")
|
|
actual_lines = File.read(tempfile_loc(name)).split("\n")
|
|
if actual_lines.first == "/*" && expected_lines.first != "/*"
|
|
assert(false, actual_lines[0..actual_lines.enum_with_index.find {|l, i| l == "*/"}.last].join("\n"))
|
|
end
|
|
end
|
|
|
|
def assert_callback(name, *expected_args)
|
|
run = false
|
|
Sass::Plugin.send("on_#{name}") do |*args|
|
|
run ||= expected_args.zip(args).all? do |ea, a|
|
|
ea.respond_to?(:call) ? ea.call(a) : ea == a
|
|
end
|
|
end
|
|
|
|
if block_given?
|
|
yield
|
|
else
|
|
Sass::Plugin.update_stylesheets
|
|
end
|
|
|
|
assert run, "Expected #{name} callback to be run with arguments:\n #{expected_args.inspect}"
|
|
end
|
|
|
|
def assert_no_callback(name, *unexpected_args)
|
|
Sass::Plugin.send("on_#{name}") do |*a|
|
|
next unless unexpected_args.empty? || a == unexpected_args
|
|
|
|
msg = "Expected #{name} callback not to be run"
|
|
if !unexpected_args.empty?
|
|
msg << " with arguments #{unexpected_args.inspect}"
|
|
elsif !a.empty?
|
|
msg << ",\n was run with arguments #{a.inspect}"
|
|
end
|
|
|
|
flunk msg
|
|
end
|
|
|
|
if block_given?
|
|
yield
|
|
else
|
|
Sass::Plugin.update_stylesheets
|
|
end
|
|
end
|
|
|
|
def assert_callbacks(*args)
|
|
return Sass::Plugin.update_stylesheets if args.empty?
|
|
assert_callback(*args.pop) {assert_callbacks(*args)}
|
|
end
|
|
|
|
def assert_no_callbacks(*args)
|
|
return Sass::Plugin.update_stylesheets if args.empty?
|
|
assert_no_callback(*args.pop) {assert_no_callbacks(*args)}
|
|
end
|
|
|
|
def clear_callbacks
|
|
Sass::Plugin.instance_variable_set('@_sass_callbacks', {})
|
|
end
|
|
|
|
def assert_needs_update(name)
|
|
assert(Sass::Plugin.stylesheet_needs_update?(tempfile_loc(name), template_loc(name)),
|
|
"Expected #{template_loc(name)} to need an update.")
|
|
end
|
|
|
|
def assert_doesnt_need_update(name)
|
|
assert(!Sass::Plugin.stylesheet_needs_update?(tempfile_loc(name), template_loc(name)),
|
|
"Expected #{template_loc(name)} not to need an update.")
|
|
end
|
|
|
|
def touch(*args)
|
|
FileUtils.touch(template_loc(*args))
|
|
end
|
|
|
|
def reset_mtimes
|
|
atime = Time.now
|
|
mtime = Time.now - 5
|
|
Dir["{#{template_loc},#{tempfile_loc}}/**/*.{css,sass,scss}"].each {|f| File.utime(atime, mtime, f)}
|
|
end
|
|
|
|
def template_loc(name = nil, prefix = nil)
|
|
if name
|
|
scss = absolutize "#{prefix}templates/#{name}.scss"
|
|
File.exists?(scss) ? scss : absolutize("#{prefix}templates/#{name}.sass")
|
|
else
|
|
absolutize "#{prefix}templates"
|
|
end
|
|
end
|
|
|
|
def tempfile_loc(name = nil, prefix = nil)
|
|
if name
|
|
absolutize "#{prefix}tmp/#{name}.css"
|
|
else
|
|
absolutize "#{prefix}tmp"
|
|
end
|
|
end
|
|
|
|
def result_loc(name = nil, prefix = nil)
|
|
if name
|
|
absolutize "#{prefix}results/#{name}.css"
|
|
else
|
|
absolutize "#{prefix}results"
|
|
end
|
|
end
|
|
|
|
def absolutize(file)
|
|
"#{File.dirname(__FILE__)}/#{file}"
|
|
end
|
|
|
|
def set_plugin_opts(overrides = {})
|
|
Sass::Plugin.options = {
|
|
:template_location => template_loc,
|
|
:css_location => tempfile_loc,
|
|
:style => :compact,
|
|
:load_paths => [result_loc],
|
|
:always_update => true,
|
|
:never_update => false,
|
|
}.merge(overrides)
|
|
end
|
|
end
|
|
|
|
module Sass::Plugin
|
|
class << self
|
|
public :stylesheet_needs_update?
|
|
end
|
|
end
|
|
|
|
class Sass::Engine
|
|
alias_method :old_render, :render
|
|
|
|
def render
|
|
raise "bork bork bork!" if @template[0] == "{bork now!}"
|
|
old_render
|
|
end
|
|
end
|