1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
|
# coding: utf-8
if RUBY_VERSION >= '1.9.1'
Encoding.default_external = "UTF-8"
end
require 'contest'
require 'tilt'
require 'tempfile'
class TiltTemplateTest < Test::Unit::TestCase
class MockTemplate < Tilt::Template
def prepare
end
end
test "needs a file or block" do
assert_raise(ArgumentError) { Tilt::Template.new }
end
test "initializing with a file" do
inst = MockTemplate.new('foo.erb') {}
assert_equal 'foo.erb', inst.file
end
test "initializing with a file and line" do
inst = MockTemplate.new('foo.erb', 55) {}
assert_equal 'foo.erb', inst.file
assert_equal 55, inst.line
end
test "initializing with a tempfile" do
tempfile = Tempfile.new('tilt_template_test')
inst = MockTemplate.new(tempfile)
assert_equal File.basename(tempfile.path), inst.basename
end
class SillyHash < Hash
def path(arg)
end
end
test "initialize with hash that implements #path" do
options = SillyHash[:key => :value]
inst = MockTemplate.new(options) {}
assert_equal :value, inst.options[:key]
end
test "uses correct eval_file" do
inst = MockTemplate.new('foo.erb', 55) {}
assert_equal 'foo.erb', inst.eval_file
end
test "uses a default filename for #eval_file when no file provided" do
inst = MockTemplate.new { 'Hi' }
assert_not_nil inst.eval_file
assert !inst.eval_file.include?("\n")
end
test "calculating template's #basename" do
inst = MockTemplate.new('/tmp/templates/foo.html.erb') {}
assert_equal 'foo.html.erb', inst.basename
end
test "calculating the template's #name" do
inst = MockTemplate.new('/tmp/templates/foo.html.erb') {}
assert_equal 'foo', inst.name
end
test "initializing with a data loading block" do
MockTemplate.new { |template| "Hello World!" }
end
class InitializingMockTemplate < Tilt::Template
@@initialized_count = 0
def self.initialized_count
@@initialized_count
end
def initialize_engine
@@initialized_count += 1
end
def prepare
end
end
test "one-time template engine initialization" do
assert_nil InitializingMockTemplate.engine_initialized
assert_equal 0, InitializingMockTemplate.initialized_count
InitializingMockTemplate.new { "Hello World!" }
assert InitializingMockTemplate.engine_initialized
assert_equal 1, InitializingMockTemplate.initialized_count
InitializingMockTemplate.new { "Hello World!" }
assert_equal 1, InitializingMockTemplate.initialized_count
end
class PreparingMockTemplate < Tilt::Template
include Test::Unit::Assertions
def prepare
assert !data.nil?
@prepared = true
end
def prepared? ; @prepared ; end
end
test "raises NotImplementedError when #prepare not defined" do
assert_raise(NotImplementedError) { Tilt::Template.new { |template| "Hello World!" } }
end
test "raises NotImplementedError when #evaluate or #template_source not defined" do
inst = PreparingMockTemplate.new { |t| "Hello World!" }
assert_raise(NotImplementedError) { inst.render }
assert inst.prepared?
end
class SimpleMockTemplate < PreparingMockTemplate
include Test::Unit::Assertions
def evaluate(scope, locals, &block)
assert prepared?
assert !scope.nil?
assert !locals.nil?
"<em>#{@data}</em>"
end
end
test "prepares and evaluates the template on #render" do
inst = SimpleMockTemplate.new { |t| "Hello World!" }
assert_equal "<em>Hello World!</em>", inst.render
assert inst.prepared?
end
class SourceGeneratingMockTemplate < PreparingMockTemplate
def precompiled_template(locals)
"foo = [] ; foo << %Q{#{data}} ; foo.join"
end
end
test "template_source with locals" do
inst = SourceGeneratingMockTemplate.new { |t| 'Hey #{name}!' }
assert_equal "Hey Joe!", inst.render(Object.new, :name => 'Joe')
assert inst.prepared?
end
test "template_source with locals of strings" do
inst = SourceGeneratingMockTemplate.new { |t| 'Hey #{name}!' }
assert_equal "Hey Joe!", inst.render(Object.new, 'name' => 'Joe')
assert inst.prepared?
end
test "template_source with locals having non-variable keys raises error" do
inst = SourceGeneratingMockTemplate.new { |t| '1 + 2 = #{_answer}' }
err = assert_raise(RuntimeError) { inst.render(Object.new, 'ANSWER' => 3) }
assert_equal "invalid locals key: \"ANSWER\" (keys must be variable names)", err.message
assert_equal "1 + 2 = 3", inst.render(Object.new, '_answer' => 3)
end
class CustomGeneratingMockTemplate < PreparingMockTemplate
def precompiled_template(locals)
data
end
def precompiled_preamble(locals)
options.fetch(:preamble)
end
def precompiled_postamble(locals)
options.fetch(:postamble)
end
end
test "supports pre/postamble" do
inst = CustomGeneratingMockTemplate.new(
:preamble => 'buf = []',
:postamble => 'buf.join'
) { 'buf << 1' }
assert_equal "1", inst.render
end
# Special-case for Haml
# https://github.com/rtomayko/tilt/issues/193
test "supports Array pre/postambles" do
inst = CustomGeneratingMockTemplate.new(
:preamble => ['buf = ', '[]'],
:postamble => ['buf.', 'join']
) { 'buf << 1' }
# TODO: Use assert_output when we swicth to MiniTest
warns = <<-EOF
precompiled_preamble should return String (not Array)
precompiled_postamble should return String (not Array)
EOF
begin
require 'stringio'
$stderr = StringIO.new
assert_equal "1", inst.render
assert_equal warns, $stderr.string
ensure
$stderr = STDERR
end
end
class Person
CONSTANT = "Bob"
attr_accessor :name
def initialize(name)
@name = name
end
end
test "template_source with an object scope" do
inst = SourceGeneratingMockTemplate.new { |t| 'Hey #{@name}!' }
scope = Person.new('Joe')
assert_equal "Hey Joe!", inst.render(scope)
end
test "template_source with a block for yield" do
inst = SourceGeneratingMockTemplate.new { |t| 'Hey #{yield}!' }
assert_equal "Hey Joe!", inst.render(Object.new){ 'Joe' }
end
test "template which accesses a constant" do
inst = SourceGeneratingMockTemplate.new { |t| 'Hey #{CONSTANT}!' }
assert_equal "Hey Bob!", inst.render(Person.new("Joe"))
end
##
# Encodings
class DynamicMockTemplate < MockTemplate
def precompiled_template(locals)
options[:code]
end
end
class UTF8Template < MockTemplate
def default_encoding
Encoding::UTF_8
end
end
if ''.respond_to?(:encoding)
original_encoding = Encoding.default_external
setup do
@file = Tempfile.open('template')
@file.puts "stuff"
@file.close
@template = @file.path
end
teardown do
Encoding.default_external = original_encoding
Encoding.default_internal = nil
@file.delete
end
test "reading from file assumes default external encoding" do
Encoding.default_external = 'Big5'
inst = MockTemplate.new(@template)
assert_equal 'Big5', inst.data.encoding.to_s
end
test "reading from file with a :default_encoding overrides default external" do
Encoding.default_external = 'Big5'
inst = MockTemplate.new(@template, :default_encoding => 'GBK')
assert_equal 'GBK', inst.data.encoding.to_s
end
test "reading from file with default_internal set does no transcoding" do
Encoding.default_internal = 'utf-8'
Encoding.default_external = 'Big5'
inst = MockTemplate.new(@template)
assert_equal 'Big5', inst.data.encoding.to_s
end
test "using provided template data verbatim when given as string" do
Encoding.default_internal = 'Big5'
inst = MockTemplate.new(@template) { "blah".force_encoding('GBK') }
assert_equal 'GBK', inst.data.encoding.to_s
end
test "uses the template from the generated source code" do
tmpl = "ふが"
code = tmpl.inspect.encode('Shift_JIS')
inst = DynamicMockTemplate.new(:code => code) { '' }
res = inst.render
assert_equal 'Shift_JIS', res.encoding.to_s
assert_equal tmpl, res.encode(tmpl.encoding)
end
test "uses the magic comment from the generated source code" do
tmpl = "ふが"
code = ("# coding: Shift_JIS\n" + tmpl.inspect).encode('Shift_JIS')
# Set it to an incorrect encoding
code.force_encoding('UTF-8')
inst = DynamicMockTemplate.new(:code => code) { '' }
res = inst.render
assert_equal 'Shift_JIS', res.encoding.to_s
assert_equal tmpl, res.encode(tmpl.encoding)
end
test "uses #default_encoding instead of default_external" do
Encoding.default_external = 'Big5'
inst = UTF8Template.new(@template)
assert_equal 'UTF-8', inst.data.encoding.to_s
end
test "uses #default_encoding instead of current encoding" do
tmpl = "".force_encoding('Big5')
inst = UTF8Template.new(@template) { tmpl }
assert_equal 'UTF-8', inst.data.encoding.to_s
end
test "raises error if the encoding is not valid" do
assert_raises(Encoding::InvalidByteSequenceError) do
UTF8Template.new(@template) { "\xe4" }
end
end
end
end
|