#!/usr/bin/env ruby require 'minitest/autorun' require File.dirname(__FILE__) + '/../test_helper' require 'sass/plugin' require 'sass/plugin/compiler' class CompilerTest < MiniTest::Test class FakeListener attr_accessor :options attr_accessor :directories attr_reader :start_called attr_reader :thread def initialize(*args, &on_filesystem_event) self.options = args.last.is_a?(Hash) ? args.pop : {} self.directories = args @on_filesystem_event = on_filesystem_event @start_called = false reset_events! end def fire_events!(*args) @on_filesystem_event.call(@modified, @added, @removed) reset_events! end def changed(filename) @modified << File.expand_path(filename) end def added(filename) @added << File.expand_path(filename) end def removed(filename) @removed << File.expand_path(filename) end def on_start!(&run_during_start) @run_during_start = run_during_start end # used for Listen < 2.0 def start! @run_during_start.call(self) if @run_during_start end # used for Listen >= 2.0 def start parent = Thread.current @thread = Thread.new do @run_during_start.call(self) if @run_during_start parent.raise Interrupt end end def stop end def reset_events! @modified = [] @added = [] @removed = [] end end module MockWatcher attr_accessor :run_during_start attr_accessor :update_stylesheets_times attr_accessor :update_stylesheets_called_with attr_accessor :deleted_css_files def fake_listener @fake_listener end def update_stylesheets(individual_files) @update_stylesheets_times ||= 0 @update_stylesheets_times += 1 (@update_stylesheets_called_with ||= []) << individual_files end def try_delete_css(css_filename) (@deleted_css_files ||= []) << css_filename end private def create_listener(*args, &on_filesystem_event) if Sass::Util.listen_geq_2? args.pop if args.last.is_a?(Hash) args.map do |dir| @fake_listener = FakeListener.new(*args, &on_filesystem_event) @fake_listener.on_start!(&run_during_start) @fake_listener end else @fake_listener = FakeListener.new(*args, &on_filesystem_event) @fake_listener.on_start!(&run_during_start) @fake_listener end end end def test_initialize watcher end def test_watch_starts_the_listener start_called = false c = watcher do |listener| start_called = true end c.watch assert start_called, "start! was not called" end def test_sass_callbacks_fire_from_listener_events c = watcher do |listener| listener.changed "changed.scss" listener.added "added.scss" listener.removed "removed.scss" listener.fire_events! end modified_fired = false c.on_template_modified do |sass_file| modified_fired = true assert_equal "changed.scss", sass_file end added_fired = false c.on_template_created do |sass_file| added_fired = true assert_equal "added.scss", sass_file end removed_fired = false c.on_template_deleted do |sass_file| removed_fired = true assert_equal "removed.scss", sass_file end c.watch assert_equal 2, c.update_stylesheets_times assert modified_fired assert added_fired assert removed_fired end def test_removing_a_sass_file_removes_corresponding_css_file c = watcher do |listener| listener.removed "remove_me.scss" listener.fire_events! end c.watch assert_equal "./remove_me.css", c.deleted_css_files.first end def test_an_importer_can_watch_an_image image_importer = Sass::Importers::Filesystem.new(".") class << image_importer def watched_file?(filename) filename =~ /\.png$/ end end c = watcher(:load_paths => [image_importer]) do |listener| listener.changed "image.png" listener.fire_events! end modified_fired = false c.on_template_modified do |f| modified_fired = true assert_equal "image.png", f end c.watch assert_equal 2, c.update_stylesheets_times assert modified_fired end def test_watching_specific_files_and_one_is_deleted directories = nil c = watcher do |listener| directories = listener.directories listener.removed File.expand_path("./foo.scss") listener.fire_events! end c.watch([[File.expand_path("./foo.scss"), File.expand_path("./foo.css"), nil]]) assert directories.include?(File.expand_path(".")), directories.inspect assert_equal File.expand_path("./foo.css"), c.deleted_css_files.first, "the corresponding css file was not deleted" assert_equal [], c.update_stylesheets_called_with[1], "the sass file should not have been compiled" end def test_watched_directories_are_dedupped directories = nil c = watcher(:load_paths => [".", "./foo", "."]) do |listener| directories = listener.directories end c.watch assert_equal [File.expand_path(".")], directories end def test_a_changed_css_in_a_watched_directory_does_not_force_a_compile c = watcher do |listener| listener.changed "foo.css" listener.fire_events! end c.on_template_modified do |f| assert false, "Should not have been called" end c.watch assert_equal 1, c.update_stylesheets_times end private def default_options {:template_location => [[".","."]]} end def watcher(options = {}, &run_during_start) options = default_options.merge(options) watcher = Sass::Plugin::Compiler.new(options) watcher.extend(MockWatcher) watcher.run_during_start = run_during_start watcher end end