xass 0.1.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 (242) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +11 -0
  3. data/CONTRIBUTING +3 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +201 -0
  6. data/Rakefile +349 -0
  7. data/VERSION +1 -0
  8. data/VERSION_NAME +1 -0
  9. data/bin/push +13 -0
  10. data/bin/sass +13 -0
  11. data/bin/sass-convert +12 -0
  12. data/bin/scss +13 -0
  13. data/extra/update_watch.rb +13 -0
  14. data/init.rb +18 -0
  15. data/lib/sass/cache_stores/base.rb +88 -0
  16. data/lib/sass/cache_stores/chain.rb +33 -0
  17. data/lib/sass/cache_stores/filesystem.rb +64 -0
  18. data/lib/sass/cache_stores/memory.rb +47 -0
  19. data/lib/sass/cache_stores/null.rb +25 -0
  20. data/lib/sass/cache_stores.rb +15 -0
  21. data/lib/sass/callbacks.rb +66 -0
  22. data/lib/sass/css.rb +409 -0
  23. data/lib/sass/engine.rb +930 -0
  24. data/lib/sass/environment.rb +101 -0
  25. data/lib/sass/error.rb +201 -0
  26. data/lib/sass/exec.rb +707 -0
  27. data/lib/sass/importers/base.rb +139 -0
  28. data/lib/sass/importers/filesystem.rb +186 -0
  29. data/lib/sass/importers.rb +22 -0
  30. data/lib/sass/logger/base.rb +32 -0
  31. data/lib/sass/logger/log_level.rb +49 -0
  32. data/lib/sass/logger.rb +15 -0
  33. data/lib/sass/media.rb +213 -0
  34. data/lib/sass/plugin/compiler.rb +406 -0
  35. data/lib/sass/plugin/configuration.rb +123 -0
  36. data/lib/sass/plugin/generic.rb +15 -0
  37. data/lib/sass/plugin/merb.rb +48 -0
  38. data/lib/sass/plugin/rack.rb +60 -0
  39. data/lib/sass/plugin/rails.rb +47 -0
  40. data/lib/sass/plugin/staleness_checker.rb +199 -0
  41. data/lib/sass/plugin.rb +133 -0
  42. data/lib/sass/railtie.rb +10 -0
  43. data/lib/sass/repl.rb +57 -0
  44. data/lib/sass/root.rb +7 -0
  45. data/lib/sass/script/arg_list.rb +52 -0
  46. data/lib/sass/script/bool.rb +18 -0
  47. data/lib/sass/script/color.rb +606 -0
  48. data/lib/sass/script/css_lexer.rb +29 -0
  49. data/lib/sass/script/css_parser.rb +31 -0
  50. data/lib/sass/script/funcall.rb +245 -0
  51. data/lib/sass/script/functions.rb +1543 -0
  52. data/lib/sass/script/interpolation.rb +79 -0
  53. data/lib/sass/script/lexer.rb +345 -0
  54. data/lib/sass/script/list.rb +85 -0
  55. data/lib/sass/script/literal.rb +221 -0
  56. data/lib/sass/script/node.rb +99 -0
  57. data/lib/sass/script/null.rb +37 -0
  58. data/lib/sass/script/number.rb +453 -0
  59. data/lib/sass/script/operation.rb +110 -0
  60. data/lib/sass/script/parser.rb +502 -0
  61. data/lib/sass/script/string.rb +51 -0
  62. data/lib/sass/script/string_interpolation.rb +103 -0
  63. data/lib/sass/script/unary_operation.rb +69 -0
  64. data/lib/sass/script/variable.rb +58 -0
  65. data/lib/sass/script.rb +39 -0
  66. data/lib/sass/scss/css_parser.rb +36 -0
  67. data/lib/sass/scss/parser.rb +1180 -0
  68. data/lib/sass/scss/rx.rb +133 -0
  69. data/lib/sass/scss/script_lexer.rb +15 -0
  70. data/lib/sass/scss/script_parser.rb +25 -0
  71. data/lib/sass/scss/static_parser.rb +54 -0
  72. data/lib/sass/scss.rb +16 -0
  73. data/lib/sass/selector/abstract_sequence.rb +94 -0
  74. data/lib/sass/selector/comma_sequence.rb +92 -0
  75. data/lib/sass/selector/sequence.rb +507 -0
  76. data/lib/sass/selector/simple.rb +119 -0
  77. data/lib/sass/selector/simple_sequence.rb +215 -0
  78. data/lib/sass/selector.rb +452 -0
  79. data/lib/sass/shared.rb +76 -0
  80. data/lib/sass/supports.rb +229 -0
  81. data/lib/sass/tree/charset_node.rb +22 -0
  82. data/lib/sass/tree/comment_node.rb +82 -0
  83. data/lib/sass/tree/content_node.rb +9 -0
  84. data/lib/sass/tree/css_import_node.rb +60 -0
  85. data/lib/sass/tree/debug_node.rb +18 -0
  86. data/lib/sass/tree/directive_node.rb +42 -0
  87. data/lib/sass/tree/each_node.rb +24 -0
  88. data/lib/sass/tree/extend_node.rb +36 -0
  89. data/lib/sass/tree/for_node.rb +36 -0
  90. data/lib/sass/tree/function_node.rb +34 -0
  91. data/lib/sass/tree/if_node.rb +52 -0
  92. data/lib/sass/tree/import_node.rb +75 -0
  93. data/lib/sass/tree/media_node.rb +58 -0
  94. data/lib/sass/tree/mixin_def_node.rb +38 -0
  95. data/lib/sass/tree/mixin_node.rb +39 -0
  96. data/lib/sass/tree/node.rb +196 -0
  97. data/lib/sass/tree/prop_node.rb +152 -0
  98. data/lib/sass/tree/return_node.rb +18 -0
  99. data/lib/sass/tree/root_node.rb +78 -0
  100. data/lib/sass/tree/rule_node.rb +132 -0
  101. data/lib/sass/tree/supports_node.rb +51 -0
  102. data/lib/sass/tree/trace_node.rb +32 -0
  103. data/lib/sass/tree/variable_node.rb +30 -0
  104. data/lib/sass/tree/visitors/base.rb +75 -0
  105. data/lib/sass/tree/visitors/check_nesting.rb +147 -0
  106. data/lib/sass/tree/visitors/convert.rb +316 -0
  107. data/lib/sass/tree/visitors/cssize.rb +241 -0
  108. data/lib/sass/tree/visitors/deep_copy.rb +102 -0
  109. data/lib/sass/tree/visitors/extend.rb +68 -0
  110. data/lib/sass/tree/visitors/perform.rb +446 -0
  111. data/lib/sass/tree/visitors/set_options.rb +125 -0
  112. data/lib/sass/tree/visitors/to_css.rb +228 -0
  113. data/lib/sass/tree/warn_node.rb +18 -0
  114. data/lib/sass/tree/while_node.rb +18 -0
  115. data/lib/sass/util/multibyte_string_scanner.rb +155 -0
  116. data/lib/sass/util/subset_map.rb +109 -0
  117. data/lib/sass/util/test.rb +10 -0
  118. data/lib/sass/util.rb +948 -0
  119. data/lib/sass/version.rb +126 -0
  120. data/lib/sass.rb +95 -0
  121. data/rails/init.rb +1 -0
  122. data/test/Gemfile +3 -0
  123. data/test/Gemfile.lock +10 -0
  124. data/test/sass/cache_test.rb +89 -0
  125. data/test/sass/callbacks_test.rb +61 -0
  126. data/test/sass/conversion_test.rb +1760 -0
  127. data/test/sass/css2sass_test.rb +458 -0
  128. data/test/sass/data/hsl-rgb.txt +319 -0
  129. data/test/sass/engine_test.rb +3244 -0
  130. data/test/sass/exec_test.rb +86 -0
  131. data/test/sass/extend_test.rb +1482 -0
  132. data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  133. data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  134. data/test/sass/functions_test.rb +1139 -0
  135. data/test/sass/importer_test.rb +192 -0
  136. data/test/sass/logger_test.rb +58 -0
  137. data/test/sass/mock_importer.rb +49 -0
  138. data/test/sass/more_results/more1.css +9 -0
  139. data/test/sass/more_results/more1_with_line_comments.css +26 -0
  140. data/test/sass/more_results/more_import.css +29 -0
  141. data/test/sass/more_templates/_more_partial.sass +2 -0
  142. data/test/sass/more_templates/more1.sass +23 -0
  143. data/test/sass/more_templates/more_import.sass +11 -0
  144. data/test/sass/plugin_test.rb +564 -0
  145. data/test/sass/results/alt.css +4 -0
  146. data/test/sass/results/basic.css +9 -0
  147. data/test/sass/results/cached_import_option.css +3 -0
  148. data/test/sass/results/compact.css +5 -0
  149. data/test/sass/results/complex.css +86 -0
  150. data/test/sass/results/compressed.css +1 -0
  151. data/test/sass/results/expanded.css +19 -0
  152. data/test/sass/results/filename_fn.css +3 -0
  153. data/test/sass/results/if.css +3 -0
  154. data/test/sass/results/import.css +31 -0
  155. data/test/sass/results/import_charset.css +5 -0
  156. data/test/sass/results/import_charset_1_8.css +5 -0
  157. data/test/sass/results/import_charset_ibm866.css +5 -0
  158. data/test/sass/results/import_content.css +1 -0
  159. data/test/sass/results/line_numbers.css +49 -0
  160. data/test/sass/results/mixins.css +95 -0
  161. data/test/sass/results/multiline.css +24 -0
  162. data/test/sass/results/nested.css +22 -0
  163. data/test/sass/results/options.css +1 -0
  164. data/test/sass/results/parent_ref.css +13 -0
  165. data/test/sass/results/script.css +16 -0
  166. data/test/sass/results/scss_import.css +31 -0
  167. data/test/sass/results/scss_importee.css +2 -0
  168. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  169. data/test/sass/results/subdir/subdir.css +3 -0
  170. data/test/sass/results/units.css +11 -0
  171. data/test/sass/results/warn.css +0 -0
  172. data/test/sass/results/warn_imported.css +0 -0
  173. data/test/sass/script_conversion_test.rb +299 -0
  174. data/test/sass/script_test.rb +622 -0
  175. data/test/sass/scss/css_test.rb +1100 -0
  176. data/test/sass/scss/rx_test.rb +156 -0
  177. data/test/sass/scss/scss_test.rb +2106 -0
  178. data/test/sass/scss/test_helper.rb +37 -0
  179. data/test/sass/templates/_cached_import_option_partial.scss +1 -0
  180. data/test/sass/templates/_double_import_loop2.sass +1 -0
  181. data/test/sass/templates/_filename_fn_import.scss +11 -0
  182. data/test/sass/templates/_imported_charset_ibm866.sass +4 -0
  183. data/test/sass/templates/_imported_charset_utf8.sass +4 -0
  184. data/test/sass/templates/_imported_content.sass +3 -0
  185. data/test/sass/templates/_partial.sass +2 -0
  186. data/test/sass/templates/_same_name_different_partiality.scss +1 -0
  187. data/test/sass/templates/alt.sass +16 -0
  188. data/test/sass/templates/basic.sass +23 -0
  189. data/test/sass/templates/bork1.sass +2 -0
  190. data/test/sass/templates/bork2.sass +2 -0
  191. data/test/sass/templates/bork3.sass +2 -0
  192. data/test/sass/templates/bork4.sass +2 -0
  193. data/test/sass/templates/bork5.sass +3 -0
  194. data/test/sass/templates/cached_import_option.scss +3 -0
  195. data/test/sass/templates/compact.sass +17 -0
  196. data/test/sass/templates/complex.sass +305 -0
  197. data/test/sass/templates/compressed.sass +15 -0
  198. data/test/sass/templates/double_import_loop1.sass +1 -0
  199. data/test/sass/templates/expanded.sass +17 -0
  200. data/test/sass/templates/filename_fn.scss +18 -0
  201. data/test/sass/templates/if.sass +11 -0
  202. data/test/sass/templates/import.sass +12 -0
  203. data/test/sass/templates/import_charset.sass +9 -0
  204. data/test/sass/templates/import_charset_1_8.sass +6 -0
  205. data/test/sass/templates/import_charset_ibm866.sass +11 -0
  206. data/test/sass/templates/import_content.sass +4 -0
  207. data/test/sass/templates/importee.less +2 -0
  208. data/test/sass/templates/importee.sass +19 -0
  209. data/test/sass/templates/line_numbers.sass +13 -0
  210. data/test/sass/templates/mixin_bork.sass +5 -0
  211. data/test/sass/templates/mixins.sass +76 -0
  212. data/test/sass/templates/multiline.sass +20 -0
  213. data/test/sass/templates/nested.sass +25 -0
  214. data/test/sass/templates/nested_bork1.sass +2 -0
  215. data/test/sass/templates/nested_bork2.sass +2 -0
  216. data/test/sass/templates/nested_bork3.sass +2 -0
  217. data/test/sass/templates/nested_bork4.sass +2 -0
  218. data/test/sass/templates/nested_import.sass +2 -0
  219. data/test/sass/templates/nested_mixin_bork.sass +6 -0
  220. data/test/sass/templates/options.sass +2 -0
  221. data/test/sass/templates/parent_ref.sass +25 -0
  222. data/test/sass/templates/same_name_different_ext.sass +2 -0
  223. data/test/sass/templates/same_name_different_ext.scss +1 -0
  224. data/test/sass/templates/same_name_different_partiality.scss +1 -0
  225. data/test/sass/templates/script.sass +101 -0
  226. data/test/sass/templates/scss_import.scss +11 -0
  227. data/test/sass/templates/scss_importee.scss +1 -0
  228. data/test/sass/templates/single_import_loop.sass +1 -0
  229. data/test/sass/templates/subdir/import_up1.scss +1 -0
  230. data/test/sass/templates/subdir/import_up2.scss +1 -0
  231. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
  232. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  233. data/test/sass/templates/subdir/subdir.sass +6 -0
  234. data/test/sass/templates/units.sass +11 -0
  235. data/test/sass/templates/warn.sass +3 -0
  236. data/test/sass/templates/warn_imported.sass +4 -0
  237. data/test/sass/test_helper.rb +8 -0
  238. data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
  239. data/test/sass/util/subset_map_test.rb +91 -0
  240. data/test/sass/util_test.rb +382 -0
  241. data/test/test_helper.rb +80 -0
  242. metadata +354 -0
@@ -0,0 +1,564 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../test_helper'
3
+ require File.dirname(__FILE__) + '/test_helper'
4
+ require 'sass/plugin'
5
+ require 'fileutils'
6
+
7
+ module Sass::Script::Functions
8
+ def filename
9
+ filename = options[:filename].gsub(%r{.*((/[^/]+){4})}, '\1')
10
+ Sass::Script::String.new(filename)
11
+ end
12
+
13
+ def whatever
14
+ custom = options[:custom]
15
+ whatever = custom && custom[:whatever]
16
+ Sass::Script::String.new(whatever || "incorrect")
17
+ end
18
+ end
19
+
20
+ class SassPluginTest < Test::Unit::TestCase
21
+ @@templates = %w{
22
+ complex script parent_ref import scss_import alt
23
+ subdir/subdir subdir/nested_subdir/nested_subdir
24
+ options import_content filename_fn
25
+ }
26
+ @@templates += %w[import_charset import_charset_ibm866] unless Sass::Util.ruby1_8?
27
+ @@templates << 'import_charset_1_8' if Sass::Util.ruby1_8?
28
+
29
+ @@cache_store = Sass::CacheStores::Memory.new
30
+
31
+ def setup
32
+ FileUtils.mkdir_p tempfile_loc
33
+ FileUtils.mkdir_p tempfile_loc(nil,"more_")
34
+ set_plugin_opts
35
+ check_for_updates!
36
+ reset_mtimes
37
+ end
38
+
39
+ def teardown
40
+ clean_up_sassc
41
+ Sass::Plugin.reset!
42
+ FileUtils.rm_r tempfile_loc
43
+ FileUtils.rm_r tempfile_loc(nil,"more_")
44
+ end
45
+
46
+ @@templates.each do |name|
47
+ define_method("test_template_renders_correctly (#{name})") do
48
+ assert_renders_correctly(name)
49
+ end
50
+ end
51
+
52
+ def test_no_update
53
+ File.delete(tempfile_loc('basic'))
54
+ assert_needs_update 'basic'
55
+ check_for_updates!
56
+ assert_stylesheet_updated 'basic'
57
+ end
58
+
59
+ def test_update_needed_when_modified
60
+ touch 'basic'
61
+ assert_needs_update 'basic'
62
+ check_for_updates!
63
+ assert_stylesheet_updated 'basic'
64
+ end
65
+
66
+ def test_update_needed_when_dependency_modified
67
+ touch 'basic'
68
+ assert_needs_update 'import'
69
+ check_for_updates!
70
+ assert_stylesheet_updated 'basic'
71
+ assert_stylesheet_updated 'import'
72
+ end
73
+
74
+ def test_update_needed_when_scss_dependency_modified
75
+ touch 'scss_importee'
76
+ assert_needs_update 'import'
77
+ check_for_updates!
78
+ assert_stylesheet_updated 'scss_importee'
79
+ assert_stylesheet_updated 'import'
80
+ end
81
+
82
+ def test_scss_update_needed_when_dependency_modified
83
+ touch 'basic'
84
+ assert_needs_update 'scss_import'
85
+ check_for_updates!
86
+ assert_stylesheet_updated 'basic'
87
+ assert_stylesheet_updated 'scss_import'
88
+ end
89
+
90
+ def test_update_needed_when_nested_import_dependency_modified
91
+ touch 'basic'
92
+ assert_needs_update 'nested_import'
93
+ check_for_updates!
94
+ assert_stylesheet_updated 'basic'
95
+ assert_stylesheet_updated 'scss_import'
96
+ end
97
+
98
+ def test_no_updates_when_always_check_and_always_update_both_false
99
+ Sass::Plugin.options[:always_update] = false
100
+ Sass::Plugin.options[:always_check] = false
101
+
102
+ touch 'basic'
103
+ assert_needs_update 'basic'
104
+ check_for_updates!
105
+
106
+ # Check it's still stale
107
+ assert_needs_update 'basic'
108
+ end
109
+
110
+ def test_full_exception_handling
111
+ File.delete(tempfile_loc('bork1'))
112
+ check_for_updates!
113
+ File.open(tempfile_loc('bork1')) do |file|
114
+ assert_equal(<<CSS.strip, file.read.split("\n")[0...6].join("\n"))
115
+ /*
116
+ Syntax error: Undefined variable: "$bork".
117
+ on line 2 of #{template_loc('bork1')}
118
+
119
+ 1: bork
120
+ 2: :bork $bork
121
+ CSS
122
+ end
123
+ File.delete(tempfile_loc('bork1'))
124
+ end
125
+
126
+ def test_full_exception_with_block_comment
127
+ File.delete(tempfile_loc('bork5'))
128
+ check_for_updates!
129
+ File.open(tempfile_loc('bork5')) do |file|
130
+ assert_equal(<<CSS.strip, file.read.split("\n")[0...7].join("\n"))
131
+ /*
132
+ Syntax error: Undefined variable: "$bork".
133
+ on line 3 of #{template_loc('bork5')}
134
+
135
+ 1: bork
136
+ 2: /* foo *\\/
137
+ 3: :bork $bork
138
+ CSS
139
+ end
140
+ File.delete(tempfile_loc('bork1'))
141
+ end
142
+
143
+ def test_single_level_import_loop
144
+ File.delete(tempfile_loc('single_import_loop'))
145
+ check_for_updates!
146
+ File.open(tempfile_loc('single_import_loop')) do |file|
147
+ assert_equal(<<CSS.strip, file.read.split("\n")[0...2].join("\n"))
148
+ /*
149
+ Syntax error: An @import loop has been found: #{template_loc('single_import_loop')} imports itself
150
+ CSS
151
+ end
152
+ end
153
+
154
+ def test_double_level_import_loop
155
+ File.delete(tempfile_loc('double_import_loop1'))
156
+ check_for_updates!
157
+ File.open(tempfile_loc('double_import_loop1')) do |file|
158
+ assert_equal(<<CSS.strip, file.read.split("\n")[0...4].join("\n"))
159
+ /*
160
+ Syntax error: An @import loop has been found:
161
+ #{template_loc('double_import_loop1')} imports #{template_loc('_double_import_loop2')}
162
+ #{template_loc('_double_import_loop2')} imports #{template_loc('double_import_loop1')}
163
+ CSS
164
+ end
165
+ end
166
+
167
+ def test_import_name_cleanup
168
+ File.delete(tempfile_loc('subdir/import_up1'))
169
+ check_for_updates!
170
+ File.open(tempfile_loc('subdir/import_up1')) do |file|
171
+ assert_equal(<<CSS.strip, file.read.split("\n")[0...5].join("\n"))
172
+ /*
173
+ Syntax error: File to import not found or unreadable: ../subdir/import_up3.scss.
174
+ Load path: #{template_loc}
175
+ on line 1 of #{template_loc 'subdir/import_up2'}
176
+ from line 1 of #{template_loc 'subdir/import_up1'}
177
+ CSS
178
+ end
179
+ end
180
+
181
+ def test_nonfull_exception_handling
182
+ old_full_exception = Sass::Plugin.options[:full_exception]
183
+ Sass::Plugin.options[:full_exception] = false
184
+
185
+ File.delete(tempfile_loc('bork1'))
186
+ assert_raise(Sass::SyntaxError) {check_for_updates!}
187
+ ensure
188
+ Sass::Plugin.options[:full_exception] = old_full_exception
189
+ end
190
+
191
+ def test_two_template_directories
192
+ set_plugin_opts :template_location => {
193
+ template_loc => tempfile_loc,
194
+ template_loc(nil,'more_') => tempfile_loc(nil,'more_')
195
+ }
196
+ check_for_updates!
197
+ ['more1', 'more_import'].each { |name| assert_renders_correctly(name, :prefix => 'more_') }
198
+ end
199
+
200
+ def test_two_template_directories_with_line_annotations
201
+ set_plugin_opts :line_comments => true,
202
+ :style => :nested,
203
+ :template_location => {
204
+ template_loc => tempfile_loc,
205
+ template_loc(nil,'more_') => tempfile_loc(nil,'more_')
206
+ }
207
+ check_for_updates!
208
+ assert_renders_correctly('more1_with_line_comments', 'more1', :prefix => 'more_')
209
+ end
210
+
211
+ def test_doesnt_render_partials
212
+ assert !File.exists?(tempfile_loc('_partial'))
213
+ end
214
+
215
+ def test_template_location_array
216
+ assert_equal [[template_loc, tempfile_loc]], Sass::Plugin.template_location_array
217
+ end
218
+
219
+ def test_add_template_location
220
+ Sass::Plugin.add_template_location(template_loc(nil, "more_"), tempfile_loc(nil, "more_"))
221
+ assert_equal(
222
+ [[template_loc, tempfile_loc], [template_loc(nil, "more_"), tempfile_loc(nil, "more_")]],
223
+ Sass::Plugin.template_location_array)
224
+
225
+ touch 'more1', 'more_'
226
+ touch 'basic'
227
+ assert_needs_update "more1", "more_"
228
+ assert_needs_update "basic"
229
+ check_for_updates!
230
+ assert_doesnt_need_update "more1", "more_"
231
+ assert_doesnt_need_update "basic"
232
+ end
233
+
234
+ def test_remove_template_location
235
+ Sass::Plugin.add_template_location(template_loc(nil, "more_"), tempfile_loc(nil, "more_"))
236
+ Sass::Plugin.remove_template_location(template_loc, tempfile_loc)
237
+ assert_equal(
238
+ [[template_loc(nil, "more_"), tempfile_loc(nil, "more_")]],
239
+ Sass::Plugin.template_location_array)
240
+
241
+ touch 'more1', 'more_'
242
+ touch 'basic'
243
+ assert_needs_update "more1", "more_"
244
+ assert_needs_update "basic"
245
+ check_for_updates!
246
+ assert_doesnt_need_update "more1", "more_"
247
+ assert_needs_update "basic"
248
+ end
249
+
250
+ def test_import_same_name
251
+ assert_warning <<WARNING do
252
+ WARNING: In #{template_loc}:
253
+ There are multiple files that match the name "same_name_different_partiality.scss":
254
+ _same_name_different_partiality.scss
255
+ same_name_different_partiality.scss
256
+ WARNING
257
+ touch "_same_name_different_partiality"
258
+ assert_needs_update "same_name_different_partiality"
259
+ end
260
+ end
261
+
262
+ # Callbacks
263
+
264
+ def test_updating_stylesheets_callback
265
+ # Should run even when there's nothing to update
266
+ Sass::Plugin.options[:template_location] = nil
267
+ assert_callback :updating_stylesheets, []
268
+ end
269
+
270
+ def test_updating_stylesheets_callback_with_never_update
271
+ Sass::Plugin.options[:never_update] = true
272
+ assert_no_callback :updating_stylesheets
273
+ end
274
+
275
+ def test_updated_stylesheet_callback_for_updated_template
276
+ Sass::Plugin.options[:always_update] = false
277
+ touch 'basic'
278
+ assert_no_callback :updated_stylesheet, template_loc("complex"), tempfile_loc("complex") do
279
+ assert_callbacks(
280
+ [:updated_stylesheet, template_loc("basic"), tempfile_loc("basic")],
281
+ [:updated_stylesheet, template_loc("import"), tempfile_loc("import")])
282
+ end
283
+ end
284
+
285
+ def test_updated_stylesheet_callback_for_fresh_template
286
+ Sass::Plugin.options[:always_update] = false
287
+ assert_no_callback :updated_stylesheet
288
+ end
289
+
290
+ def test_updated_stylesheet_callback_for_error_template
291
+ Sass::Plugin.options[:always_update] = false
292
+ touch 'bork1'
293
+ assert_no_callback :updated_stylesheet
294
+ end
295
+
296
+ def test_not_updating_stylesheet_callback_for_fresh_template
297
+ Sass::Plugin.options[:always_update] = false
298
+ assert_callback :not_updating_stylesheet, template_loc("basic"), tempfile_loc("basic")
299
+ end
300
+
301
+ def test_not_updating_stylesheet_callback_for_updated_template
302
+ Sass::Plugin.options[:always_update] = false
303
+ assert_callback :not_updating_stylesheet, template_loc("complex"), tempfile_loc("complex") do
304
+ assert_no_callbacks(
305
+ [:updated_stylesheet, template_loc("basic"), tempfile_loc("basic")],
306
+ [:updated_stylesheet, template_loc("import"), tempfile_loc("import")])
307
+ end
308
+ end
309
+
310
+ def test_not_updating_stylesheet_callback_with_never_update
311
+ Sass::Plugin.options[:never_update] = true
312
+ assert_no_callback :not_updating_stylesheet
313
+ end
314
+
315
+ def test_not_updating_stylesheet_callback_for_partial
316
+ Sass::Plugin.options[:always_update] = false
317
+ assert_no_callback :not_updating_stylesheet, template_loc("_partial"), tempfile_loc("_partial")
318
+ end
319
+
320
+ def test_not_updating_stylesheet_callback_for_error
321
+ Sass::Plugin.options[:always_update] = false
322
+ touch 'bork1'
323
+ assert_no_callback :not_updating_stylesheet, template_loc("bork1"), tempfile_loc("bork1")
324
+ end
325
+
326
+ def test_compilation_error_callback
327
+ Sass::Plugin.options[:always_update] = false
328
+ touch 'bork1'
329
+ assert_callback(:compilation_error,
330
+ lambda {|e| e.message == 'Undefined variable: "$bork".'},
331
+ template_loc("bork1"), tempfile_loc("bork1"))
332
+ end
333
+
334
+ def test_compilation_error_callback_for_file_access
335
+ Sass::Plugin.options[:always_update] = false
336
+ assert_callback(:compilation_error,
337
+ lambda {|e| e.is_a?(Errno::ENOENT)},
338
+ template_loc("nonexistent"), tempfile_loc("nonexistent")) do
339
+ Sass::Plugin.update_stylesheets([[template_loc("nonexistent"), tempfile_loc("nonexistent")]])
340
+ end
341
+ end
342
+
343
+ def test_creating_directory_callback
344
+ Sass::Plugin.options[:always_update] = false
345
+ dir = File.join(tempfile_loc, "subdir", "nested_subdir")
346
+ FileUtils.rm_r dir
347
+ assert_callback :creating_directory, dir
348
+ end
349
+
350
+ ## Regression
351
+
352
+ def test_cached_dependencies_update
353
+ FileUtils.mv(template_loc("basic"), template_loc("basic", "more_"))
354
+ set_plugin_opts :load_paths => [template_loc(nil, "more_")]
355
+
356
+ touch 'basic', 'more_'
357
+ assert_needs_update "import"
358
+ check_for_updates!
359
+ assert_renders_correctly("import")
360
+ ensure
361
+ FileUtils.mv(template_loc("basic", "more_"), template_loc("basic"))
362
+ end
363
+
364
+ def test_cached_relative_import
365
+ old_always_update = Sass::Plugin.options[:always_update]
366
+ Sass::Plugin.options[:always_update] = true
367
+ check_for_updates!
368
+ assert_renders_correctly('subdir/subdir')
369
+ ensure
370
+ Sass::Plugin.options[:always_update] = old_always_update
371
+ end
372
+
373
+ def test_cached_if
374
+ set_plugin_opts :cache_store => Sass::CacheStores::Filesystem.new(tempfile_loc + '/cache')
375
+ check_for_updates!
376
+ assert_renders_correctly 'if'
377
+ check_for_updates!
378
+ assert_renders_correctly 'if'
379
+ ensure
380
+ set_plugin_opts
381
+ end
382
+
383
+ def test_cached_import_option
384
+ set_plugin_opts :custom => {:whatever => "correct"}
385
+ check_for_updates!
386
+ assert_renders_correctly "cached_import_option"
387
+
388
+ @@cache_store.reset!
389
+ set_plugin_opts :custom => nil, :always_update => false
390
+ check_for_updates!
391
+ assert_renders_correctly "cached_import_option"
392
+
393
+ set_plugin_opts :custom => {:whatever => "correct"}, :always_update => true
394
+ check_for_updates!
395
+ assert_renders_correctly "cached_import_option"
396
+ ensure
397
+ set_plugin_opts :custom => nil
398
+ end
399
+
400
+ private
401
+
402
+ def assert_renders_correctly(*arguments)
403
+ options = arguments.last.is_a?(Hash) ? arguments.pop : {}
404
+ prefix = options[:prefix]
405
+ result_name = arguments.shift
406
+ tempfile_name = arguments.shift || result_name
407
+
408
+ expected_str = File.read(result_loc(result_name, prefix))
409
+ actual_str = File.read(tempfile_loc(tempfile_name, prefix))
410
+ unless Sass::Util.ruby1_8?
411
+ expected_str = expected_str.force_encoding('IBM866') if result_name == 'import_charset_ibm866'
412
+ actual_str = actual_str.force_encoding('IBM866') if tempfile_name == 'import_charset_ibm866'
413
+ end
414
+ expected_lines = expected_str.split("\n")
415
+ actual_lines = actual_str.split("\n")
416
+
417
+ if actual_lines.first == "/*" && expected_lines.first != "/*"
418
+ assert(false, actual_lines[0..Sass::Util.enum_with_index(actual_lines).find {|l, i| l == "*/"}.last].join("\n"))
419
+ end
420
+
421
+ expected_lines.zip(actual_lines).each_with_index do |pair, line|
422
+ message = "template: #{result_name}\nline: #{line + 1}"
423
+ assert_equal(pair.first, pair.last, message)
424
+ end
425
+ if expected_lines.size < actual_lines.size
426
+ assert(false, "#{actual_lines.size - expected_lines.size} Trailing lines found in #{tempfile_name}.css: #{actual_lines[expected_lines.size..-1].join('\n')}")
427
+ end
428
+ end
429
+
430
+ def assert_stylesheet_updated(name)
431
+ assert_doesnt_need_update name
432
+
433
+ # Make sure it isn't an exception
434
+ expected_lines = File.read(result_loc(name)).split("\n")
435
+ actual_lines = File.read(tempfile_loc(name)).split("\n")
436
+ if actual_lines.first == "/*" && expected_lines.first != "/*"
437
+ assert(false, actual_lines[0..actual_lines.enum_with_index.find {|l, i| l == "*/"}.last].join("\n"))
438
+ end
439
+ end
440
+
441
+ def assert_callback(name, *expected_args)
442
+ run = false
443
+ received_args = nil
444
+ Sass::Plugin.send("on_#{name}") do |*args|
445
+ received_args = args
446
+ run ||= expected_args.zip(received_args).all? do |ea, ra|
447
+ ea.respond_to?(:call) ? ea.call(ra) : ea == ra
448
+ end
449
+ end
450
+
451
+ if block_given?
452
+ Sass::Util.silence_sass_warnings {yield}
453
+ else
454
+ check_for_updates!
455
+ end
456
+
457
+ assert run, "Expected #{name} callback to be run with arguments:\n #{expected_args.inspect}\nHowever, it got:\n #{received_args.inspect}"
458
+ end
459
+
460
+ def assert_no_callback(name, *unexpected_args)
461
+ Sass::Plugin.send("on_#{name}") do |*a|
462
+ next unless unexpected_args.empty? || a == unexpected_args
463
+
464
+ msg = "Expected #{name} callback not to be run"
465
+ if !unexpected_args.empty?
466
+ msg << " with arguments #{unexpected_args.inspect}"
467
+ elsif !a.empty?
468
+ msg << ",\n was run with arguments #{a.inspect}"
469
+ end
470
+
471
+ flunk msg
472
+ end
473
+
474
+ if block_given?
475
+ yield
476
+ else
477
+ check_for_updates!
478
+ end
479
+ end
480
+
481
+ def assert_callbacks(*args)
482
+ return check_for_updates! if args.empty?
483
+ assert_callback(*args.pop) {assert_callbacks(*args)}
484
+ end
485
+
486
+ def assert_no_callbacks(*args)
487
+ return check_for_updates! if args.empty?
488
+ assert_no_callback(*args.pop) {assert_no_callbacks(*args)}
489
+ end
490
+
491
+ def check_for_updates!
492
+ Sass::Util.silence_sass_warnings do
493
+ Sass::Plugin.check_for_updates
494
+ end
495
+ end
496
+
497
+ def assert_needs_update(*args)
498
+ assert(Sass::Plugin::StalenessChecker.stylesheet_needs_update?(tempfile_loc(*args), template_loc(*args)),
499
+ "Expected #{template_loc(*args)} to need an update.")
500
+ end
501
+
502
+ def assert_doesnt_need_update(*args)
503
+ assert(!Sass::Plugin::StalenessChecker.stylesheet_needs_update?(tempfile_loc(*args), template_loc(*args)),
504
+ "Expected #{template_loc(*args)} not to need an update.")
505
+ end
506
+
507
+ def touch(*args)
508
+ FileUtils.touch(template_loc(*args))
509
+ end
510
+
511
+ def reset_mtimes
512
+ Sass::Plugin::StalenessChecker.dependencies_cache = {}
513
+ atime = Time.now
514
+ mtime = Time.now - 5
515
+ Dir["{#{template_loc},#{tempfile_loc}}/**/*.{css,sass,scss}"].each {|f| File.utime(atime, mtime, f)}
516
+ end
517
+
518
+ def template_loc(name = nil, prefix = nil)
519
+ if name
520
+ scss = absolutize "#{prefix}templates/#{name}.scss"
521
+ File.exists?(scss) ? scss : absolutize("#{prefix}templates/#{name}.sass")
522
+ else
523
+ absolutize "#{prefix}templates"
524
+ end
525
+ end
526
+
527
+ def tempfile_loc(name = nil, prefix = nil)
528
+ if name
529
+ absolutize "#{prefix}tmp/#{name}.css"
530
+ else
531
+ absolutize "#{prefix}tmp"
532
+ end
533
+ end
534
+
535
+ def result_loc(name = nil, prefix = nil)
536
+ if name
537
+ absolutize "#{prefix}results/#{name}.css"
538
+ else
539
+ absolutize "#{prefix}results"
540
+ end
541
+ end
542
+
543
+ def set_plugin_opts(overrides = {})
544
+ Sass::Plugin.options.merge!(
545
+ :template_location => template_loc,
546
+ :css_location => tempfile_loc,
547
+ :style => :compact,
548
+ :always_update => true,
549
+ :never_update => false,
550
+ :full_exception => true,
551
+ :cache_store => @@cache_store
552
+ )
553
+ Sass::Plugin.options.merge!(overrides)
554
+ end
555
+ end
556
+
557
+ class Sass::Engine
558
+ alias_method :old_render, :render
559
+
560
+ def render
561
+ raise "bork bork bork!" if @template[0] == "{bork now!}"
562
+ old_render
563
+ end
564
+ end
@@ -0,0 +1,4 @@
1
+ h1 { float: left; width: 274px; height: 75px; margin: 0; background-repeat: no-repeat; background-image: none; }
2
+ h1 a:hover, h1 a:visited { color: green; }
3
+ h1 b:hover { color: red; background-color: green; }
4
+ h1 const { nosp: 3; sp: 3; }
@@ -0,0 +1,9 @@
1
+ body { font: Arial; background: blue; }
2
+
3
+ #page { width: 700px; height: 100; }
4
+ #page #header { height: 300px; }
5
+ #page #header h1 { font-size: 50px; color: blue; }
6
+
7
+ #content.user.show #container.top #column.left { width: 100px; }
8
+ #content.user.show #container.top #column.right { width: 600px; }
9
+ #content.user.show #container.bottom { background: brown; }
@@ -0,0 +1,3 @@
1
+ partial { value: correct; }
2
+
3
+ main { value: correct; }
@@ -0,0 +1,5 @@
1
+ #main { width: 15em; color: blue; }
2
+ #main p { border-style: dotted; /* Nested comment More nested stuff */ border-width: 2px; }
3
+ #main .cool { width: 100px; }
4
+
5
+ #left { font-size: 2em; font-weight: bold; float: left; }
@@ -0,0 +1,86 @@
1
+ body { margin: 0; font: 0.85em "Lucida Grande", "Trebuchet MS", Verdana, sans-serif; color: white; background: url(/images/global_bg.gif); }
2
+
3
+ #page { width: 900px; margin: 0 auto; background: #440008; border-top-width: 5px; border-top-style: solid; border-top-color: #ff8500; }
4
+
5
+ #header { height: 75px; padding: 0; }
6
+ #header h1 { float: left; width: 274px; height: 75px; margin: 0; background-image: url(/images/global_logo.gif); /* Crazy nested comment */ background-repeat: no-repeat; text-indent: -9999px; }
7
+ #header .status { float: right; padding-top: 0.5em; padding-left: 0.5em; padding-right: 0.5em; padding-bottom: 0; }
8
+ #header .status p { float: left; margin-top: 0; margin-right: 0.5em; margin-bottom: 0; margin-left: 0; }
9
+ #header .status ul { float: left; margin: 0; padding: 0; }
10
+ #header .status li { list-style-type: none; display: inline; margin: 0 5px; }
11
+ #header .status a:link, #header .status a:visited { color: #ff8500; text-decoration: none; }
12
+ #header .status a:hover { text-decoration: underline; }
13
+ #header .search { float: right; clear: right; margin: 12px 0 0 0; }
14
+ #header .search form { margin: 0; }
15
+ #header .search input { margin: 0 3px 0 0; padding: 2px; border: none; }
16
+
17
+ #menu { clear: both; text-align: right; height: 20px; border-bottom: 5px solid #006b95; background: #00a4e4; }
18
+ #menu .contests ul { margin: 0 5px 0 0; padding: 0; }
19
+ #menu .contests ul li { list-style-type: none; margin: 0 5px; padding: 5px 5px 0 5px; display: inline; font-size: 1.1em; color: white; background: #00a4e4; }
20
+ #menu .contests a:link, #menu .contests a:visited { color: white; text-decoration: none; font-weight: bold; }
21
+ #menu .contests a:hover { text-decoration: underline; }
22
+
23
+ #content { clear: both; }
24
+ #content .container { clear: both; }
25
+ #content .container .column { float: left; }
26
+ #content .container .column .right { float: right; }
27
+ #content a:link, #content a:visited { color: #93d700; text-decoration: none; }
28
+ #content a:hover { text-decoration: underline; }
29
+
30
+ #content p, #content div { width: 40em; }
31
+ #content p li, #content p dt, #content p dd, #content div li, #content div dt, #content div dd { color: #ddffdd; background-color: #4792bb; }
32
+ #content .container.video .column.left { width: 200px; }
33
+ #content .container.video .column.left .box { margin-top: 10px; }
34
+ #content .container.video .column.left .box p { margin: 0 1em auto 1em; }
35
+ #content .container.video .column.left .box.participants img { float: left; margin: 0 1em auto 1em; border: 1px solid #6e000d; border-style: solid; }
36
+ #content .container.video .column.left .box.participants h2 { margin: 0 0 10px 0; padding: 0.5em; /* The background image is a gif! */ background: #6e000d url(/images/hdr_participant.gif) 2px 2px no-repeat; /* Okay check this out Multiline comments Wow dude I mean seriously, WOW */ text-indent: -9999px; border-top-width: 5px; border-top-style: solid; border-top-color: #a20013; border-right-width: 1px; border-right-style: dotted; }
37
+ #content .container.video .column.middle { width: 500px; }
38
+ #content .container.video .column.right { width: 200px; }
39
+ #content .container.video .column.right .box { margin-top: 0; }
40
+ #content .container.video .column.right .box p { margin: 0 1em auto 1em; }
41
+ #content .container.video .column p { margin-top: 0; }
42
+
43
+ #content.contests .container.information .column.right .box { margin: 1em 0; }
44
+ #content.contests .container.information .column.right .box.videos .thumbnail img { width: 200px; height: 150px; margin-bottom: 5px; }
45
+ #content.contests .container.information .column.right .box.videos a:link, #content.contests .container.information .column.right .box.videos a:visited { color: #93d700; text-decoration: none; }
46
+ #content.contests .container.information .column.right .box.videos a:hover { text-decoration: underline; }
47
+ #content.contests .container.information .column.right .box.votes a { display: block; width: 200px; height: 60px; margin: 15px 0; background: url(/images/btn_votenow.gif) no-repeat; text-indent: -9999px; outline: none; border: none; }
48
+ #content.contests .container.information .column.right .box.votes h2 { margin: 52px 0 10px 0; padding: 0.5em; background: #6e000d url(/images/hdr_videostats.gif) 2px 2px no-repeat; text-indent: -9999px; border-top: 5px solid #a20013; }
49
+
50
+ #content.contests .container.video .box.videos h2 { margin: 0; padding: 0.5em; background: #6e000d url(/images/hdr_newestclips.gif) 2px 2px no-repeat; text-indent: -9999px; border-top: 5px solid #a20013; }
51
+ #content.contests .container.video .box.videos table { width: 100; }
52
+ #content.contests .container.video .box.videos table td { padding: 1em; width: 25; vertical-align: top; }
53
+ #content.contests .container.video .box.videos table td p { margin: 0 0 5px 0; }
54
+ #content.contests .container.video .box.videos table td a:link, #content.contests .container.video .box.videos table td a:visited { color: #93d700; text-decoration: none; }
55
+ #content.contests .container.video .box.videos table td a:hover { text-decoration: underline; }
56
+ #content.contests .container.video .box.videos .thumbnail { float: left; }
57
+ #content.contests .container.video .box.videos .thumbnail img { width: 80px; height: 60px; margin: 0 10px 0 0; border: 1px solid #6e000d; }
58
+
59
+ #content .container.comments .column { margin-top: 15px; }
60
+ #content .container.comments .column.left { width: 600px; }
61
+ #content .container.comments .column.left .box ol { margin: 0; padding: 0; }
62
+ #content .container.comments .column.left .box li { list-style-type: none; padding: 10px; margin: 0 0 1em 0; background: #6e000d; border-top: 5px solid #a20013; }
63
+ #content .container.comments .column.left .box li div { margin-bottom: 1em; }
64
+ #content .container.comments .column.left .box li ul { text-align: right; }
65
+ #content .container.comments .column.left .box li ul li { display: inline; border: none; padding: 0; }
66
+ #content .container.comments .column.right { width: 290px; padding-left: 10px; }
67
+ #content .container.comments .column.right h2 { margin: 0; padding: 0.5em; background: #6e000d url(/images/hdr_addcomment.gif) 2px 2px no-repeat; text-indent: -9999px; border-top: 5px solid #a20013; }
68
+ #content .container.comments .column.right .box textarea { width: 290px; height: 100px; border: none; }
69
+
70
+ #footer { margin-top: 10px; padding: 1.2em 1.5em; background: #ff8500; }
71
+ #footer ul { margin: 0; padding: 0; list-style-type: none; }
72
+ #footer ul li { display: inline; margin: 0 0.5em; color: #440008; }
73
+ #footer ul.links { float: left; }
74
+ #footer ul.links a:link, #footer ul.links a:visited { color: #440008; text-decoration: none; }
75
+ #footer ul.links a:hover { text-decoration: underline; }
76
+ #footer ul.copyright { float: right; }
77
+
78
+ .clear { clear: both; }
79
+
80
+ .centered { text-align: center; }
81
+
82
+ img { border: none; }
83
+
84
+ button.short { width: 60px; height: 22px; padding: 0 0 2px 0; color: white; border: none; background: url(/images/btn_short.gif) no-repeat; }
85
+
86
+ table { border-collapse: collapse; }
@@ -0,0 +1 @@
1
+ #main{width:15em;color:blue}#main p{border-style:dotted;border-width:2px}#main .cool{width:100px}#left{font-size:2em;font-weight:bold;float:left}