sinatra-1.4.3/ 0000755 0000041 0000041 00000000000 12161612727 013215 5 ustar www-data www-data sinatra-1.4.3/README.hu.md 0000644 0000041 0000041 00000043751 12161612727 015121 0 ustar www-data www-data # Sinatra
*Fontos megjegyzés: Ez a dokumentum csak egy fordítása az angol nyelvű
változat, és lehet, hogy nem naprakész.*
A Sinatra egy [DSL](http://en.wikipedia.org/wiki/Domain-specific_language)
webalkalmazások Ruby nyelven történő fejlesztéséhez, minimális
energiabefektetéssel:
```ruby
# myapp.rb
require 'sinatra'
get '/' do
'Helló Világ!'
end
```
Telepítsd a gem-et és indítsd el az alkalmazást a következőképpen:
```ruby
sudo gem install sinatra
ruby myapp.rb
```
Az alkalmazás elérhető lesz itt: `http://localhost:4567`
## Útvonalak (routes)
A Sinatrában az útvonalat egy HTTP metódus és egy URL-re illeszkedő minta
párosa alkotja. Minden egyes útvonalhoz tartozik egy blokk:
```ruby
get '/' do
.. megjelenítünk valamit ..
end
post '/' do
.. létrehozunk valamit ..
end
put '/' do
.. frissítünk valamit ..
end
delete '/' do
.. törlünk valamit ..
end
```
Az útvonalak illeszkedését a rendszer a definiálásuk sorrendjében
ellenőrzi. Sorrendben mindig az első illeszkedő útvonalhoz tartozó metódus kerül
meghívásra.
Az útvonalminták tartalmazhatnak paramétereket is, melyeket a `params`
hash-ből érhetünk el:
```ruby
get '/hello/:name' do
# illeszkedik a "GET /hello/foo" és a "GET /hello/bar" útvonalakra
# ekkor params[:name] értéke 'foo' vagy 'bar' lesz
"Helló #{params[:name]}!"
end
```
A kulcsszavas argumentumokat (named parameters) blokk paraméterek útján
is el tudod érni:
```ruby
get '/hello/:name' do |n|
"Helló #{n}!"
end
```
Az útvonalmintákban szerepelhetnek joker paraméterek is, melyeket a
`params[:splat]` tömbön keresztül tudunk elérni.
```ruby
get '/say/*/to/*' do
# illeszkedik a /say/hello/to/world mintára
params[:splat] # => ["hello", "world"]
end
get '/download/*.*' do
# illeszkedik a /download/path/to/file.xml mintára
params[:splat] # => ["path/to/file", "xml"]
end
```
Reguláris kifejezéseket is felvehetünk az útvonalba:
```ruby
get %r{/hello/([\w]+)} do
"Helló, #{params[:captures].first}!"
end
```
Vagy blokk paramétereket:
```ruby
get %r{/hello/([\w]+)} do |c|
"Helló, #{c}!"
end
```
Az útvonalak azonban számos egyéb illeszkedési feltétel szerint is
tervezhetők, így például az user agent karakterláncot alapul véve:
```ruby
get '/foo', :agent => /Songbird (\d\.\d)[\d\/]*?/ do
"A Songbird #{params[:agent][0]} verzióját használod"
end
get '/foo' do
# illeszkedik az egyéb user agentekre
end
```
## Statikus állományok
A statikus fájlok kiszolgálása a `./public` könyvtárból
történik, de természetesen más könyvtárat is megadhatsz erre a célra,
mégpedig a :public_folder kapcsoló beállításával:
set :public_folder, File.dirname(__FILE__) + '/static'
Fontos mgejegyezni, hogy a nyilvános könyvtár neve nem szerepel az URL-ben.
A ./public/css/style.css fájl az
`http://example.com/css/style.css` URL-en lesz elérhető.
## Nézetek és Sablonok
A sablonfájlokat rendszerint a `./views` könyvtárba helyezzük, de
itt is lehetőség nyílik egyéb könyvtár használatára:
set :views, File.dirname(__FILE__) + '/templates'
Nagyon fontos észben tartani, hogy a sablononkra mindig szimbólumokkal
hivatkozunk, még akkor is, ha egyéb (ebben az esetben a
:'subdir/template') könyvtárban tároljuk őket. A renderelő
metódusok minden, nekik közvetlenül átadott karakterláncot megjelenítenek.
### Haml sablonok
HAML sablonok rendereléséhez szükségünk lesz a haml gem-re vagy könyvtárra:
```ruby
# Importáljuk be a haml-t az alkalmazásba
require 'haml'
get '/' do
haml :index
end
```
Ez szépen lerendereli a `./views/index.haml` sablont.
A [Haml kapcsolói](http://haml.hamptoncatlin.com/docs/rdoc/classes/Haml.html)
globálisan is beállíthatók a Sinatra konfigurációi között, lásd az
[Options and Configurations](http://www.sinatrarb.com/configuration.html) lapot.
A globális beállításokat lehetőségünk van felülírni metódus szinten is.
```ruby
set :haml, {:format => :html5 } # az alapértelmezett Haml formátum az :xhtml
get '/' do
haml :index, :haml_options => {:format => :html4 } # immár felülírva
end
```
### Erb sablonok
# Importáljuk be az erb-t az alkalmazásba
```ruby
require 'erb'
get '/' do
erb :index
end
```
Ez a `./views/index.erb` sablont fogja lerenderelni.
### Builder sablonok
Szükségünk lesz a builder gem-re vagy könyvtárra a builder sablonok
rendereléséhez:
# Importáljuk be a builder-t az alkalmazásba
```ruby
require 'builder'
get '/' do
builder :index
end
```
Ez pedig a `./views/index.builder` állományt fogja renderelni.
### Sass sablonok
Sass sablonok használatához szükség lesz a haml gem-re vagy könyvtárra:
# Be kell importálni a haml, vagy a sass könyvtárat
```ruby
require 'sass'
get '/stylesheet.css' do
sass :stylesheet
end
```
Így a `./views/stylesheet.sass` fájl máris renderelhető.
A [Sass kapcsolói](http://haml.hamptoncatlin.com/docs/rdoc/classes/Sass.html)
globálisan is beállíthatók a Sinatra konfigurációi között, lásd az
[Options and Configurations](http://www.sinatrarb.com/configuration.html) lapot.
A globális beállításokat lehetőségünk van felülírni metódus szinten is.
```ruby
set :sass, {:style => :compact } # az alapértelmezett Sass stílus a :nested
get '/stylesheet.css' do
sass :stylesheet, :sass_options => {:style => :expanded } # felülírva
end
```
### Beágyazott sablonok
```ruby
get '/' do
haml '%div.title Helló Világ'
end
```
Lerendereli a beágyazott sablon karakerláncát.
### Változók elérése a sablonokban
A sablonok ugyanabban a kontextusban kerülnek kiértékelésre, mint az
útvonal metódusok (route handlers). Az útvonal metódusokban megadott
változók közvetlenül elérhetőek lesznek a sablonokban:
```ruby
get '/:id' do
@foo = Foo.find(params[:id])
haml '%h1= @foo.name'
end
```
De megadhatod egy lokális változókat tartalmazó explicit hash-ben is:
```ruby
get '/:id' do
foo = Foo.find(params[:id])
haml '%h1= foo.name', :locals => { :foo => foo }
end
```
Ezt leginkább akkor érdemes megtenni, ha partial-eket akarunk renderelni
valamely más sablonból.
### Fájlon belüli sablonok
Sablonokat úgy is megadhatunk, hogy egyszerűen az alkalmazás fájl
végére begépeljük őket:
```ruby
require 'rubygems'
require 'sinatra'
get '/' do
haml :index
end
__END__
@@ layout
%html
= yield
@@ index
%div.title Helló Világ!!!!!
```
Megjegyzés: azok a fájlon belüli sablonok, amelyek az alkalmazás fájl végére
kerülnek és függnek a sinatra könyvtártól, automatikusan betöltődnek.
Ha ugyanezt más alkalmazásfájlban is szeretnéd megtenni, hívd meg
a use_in_file_templates! metódust az adott fájlban.
### Kulcsszavas sablonok
Sablonokat végül a felsőszintű template metódussal is
definiálhatunk:
```ruby
template :layout do
"%html\n =yield\n"
end
template :index do
'%div.title Helló Világ!'
end
get '/' do
haml :index
end
```
Ha létezik "layout" nevű sablon, akkor az minden esetben meghívódik, amikor
csak egy sablon renderelésre kerül. A layoutokat ki lehet kapcsolni a
`:layout => false` meghívásával.
```ruby
get '/' do
haml :index, :layout => !request.xhr?
end
```
## Helperek
Használd a felső szintű helpers metódust azokhoz a helper
függvényekhez, amiket az útvonal metódusokban és a sablonokban akarsz
használni:
```ruby
helpers do
def bar(name)
"#{name}bar"
end
end
get '/:name' do
bar(params[:name])
end
```
## Szűrők (filters)
Az előszűrők (before filter) az adott hívás kontextusában minden egyes
kérés alkalmával kiértékelődnek, így módosíthatják a kérést és a
választ egyaránt. A szűrőkbe felvett példányváltozók elérhetőek lesznek
az útvonalakban és a sablonokban is:
```ruby
before do
@note = 'Csá!'
request.path_info = '/foo/bar/baz'
end
get '/foo/*' do
@note #=> 'Szeva!'
params[:splat] #=> 'bar/baz'
end
```
Az utószűrők az egyes kérések után, az adott kérés kontextusában kerülnek
kiértékelésre, így ezek is képesek módosítani a kérést és a választ egyaránt.
Az előszűrőkben és úvonalakban létrehozott példányváltozók elérhetőek lesznek
az utószűrők számára:
```ruby
after do
puts response.status
end
```
## Megállítás
Egy kérés szűrőben vagy útvonalban történő azonnal blokkolásához
használd a következő parancsot:
halt
A megállításkor egy blokktörzset is megadhatsz ...
halt 'ez fog megjelenni a törzsben'
Vagy állítsd be a HTTP státuszt és a törzset is egyszerre ...
halt 401, 'menj innen!'
## Passzolás
Az útvonalak továbbadhatják a végrehajtást egy másik útvonalnak
a `pass` függvényhívással:
```ruby
get '/guess/:who' do
pass unless params[:who] == 'Frici'
"Elkaptál!"
end
get '/guess/*' do
"Elhibáztál!"
end
```
Az útvonal blokkja azonnal kilép és átadja a vezérlést a következő
illeszkedő útvonalnak. Ha nem talál megfelelő útvonalat, a Sinatra
egy 404-es hibával tér vissza.
## Beállítások
Csak indításkor, de minden környezetre érvényesen fusson le:
```ruby
configure do
...
end
```
Csak akkor fusson le, ha a környezet (a RACK_ENV környezeti változóban)
`:production`-ra van állítva:
```ruby
configure :production do
...
end
```
Csak akkor fusson le, ha a környezet :production vagy :test:
```ruby
configure :production, :test do
...
end
```
## Hibakezelés
A hibakezelők ugyanabban a kontextusban futnak le, mint az útvonalak és
előszűrők, ezért számukra is elérhetőek mindazok a könyvtárak, amelyek
az utóbbiak rendelkezésére is állnak; így például a `haml`,
az `erb`, a `halt` stb.
### Nem található
Amikor a `Sinatra::NotFound` kivétel fellép, vagy a válasz HTTP
státuszkódja 404-es, mindig a `not_found` metódus hívódik meg.
```ruby
not_found do
'Sehol sem találom, amit keresel'
end
```
### Hiba
Az `error` metódus hívódik meg olyankor, amikor egy útvonal, blokk vagy
előszűrő kivételt vált ki. A kivétel objektum lehívható a
`sinatra.error` Rack változótól:
```ruby
error do
'Elnézést, de valami szörnyű hiba lépett fel - ' + env['sinatra.error'].name
end
```
Egyéni hibakezelés:
```ruby
error MyCustomError do
'Szóval az van, hogy...' + env['sinatra.error'].message
end
```
És amikor fellép:
```ruby
get '/' do
raise MyCustomError, 'valami nem stimmel!'
end
```
Ez fog megjelenni:
Szóval az van, hogy... valami nem stimmel!
A Sinatra speciális `not_found` és `error` hibakezelőket
használ, amikor a futtatási környezet fejlesztői módba van kapcsolva.
## Mime típusok
A `send_file` metódus használatakor, vagy statikus fájlok
kiszolgálásakor előfordulhat, hogy a Sinatra nem ismeri fel a fájlok
mime típusát. Ilyenkor használd a +mime_type+ kapcsolót a fájlkiterjesztés
bevezetéséhez:
```ruby
mime_type :foo, 'text/foo'
```
## Rack Middleware
A Sinatra egy Ruby keretrendszerek számára kifejlesztett egyszerű és szabványos
interfészre, a [Rack](http://rack.rubyforge.org/) -re épül. A Rack fejlesztői
szempontból egyik legérdekesebb jellemzője, hogy támogatja az úgynevezett
"middleware" elnevezésű komponenseket, amelyek beékelődnek a szerver és az
alkalmazás közé, így képesek megfigyelni és/vagy módosítani a HTTP
kéréseket és válaszokat. Segítségükkel különféle, egységesen működő
funkciókat építhetünk be rendszerünkbe.
A Sinatra keretrendszerben gyerekjáték a Rack middleware-ek behúzása a
`use` metódus segítségével:
```ruby
require 'sinatra'
require 'my_custom_middleware'
use Rack::Lint
use MyCustomMiddleware
get '/hello' do
'Helló Világ'
end
```
A `use` metódus szemantikája megegyezik a
[Rack::Builder](http://rack.rubyforge.org/doc/classes/Rack/Builder.html) DSL-ben
használt +use+ metóduséval (az említett DSL-t leginkább rackup állományokban
használják). Hogy egy példát említsünk, a `use` metódus elfogad
változókat és blokkokat egyaránt, akár kombinálva is ezeket:
```ruby
use Rack::Auth::Basic do |username, password|
username == 'admin' && password == 'titkos'
end
```
A Rack terjesztéssel egy csomó alap middleware komponens is érkezik,
amelyekkel a naplózás, URL útvonalak megadása, autentikáció és
munkamenet-kezelés könnyen megvalósítható. A Sinatra ezek közül elég
sokat automatikusan felhasznál a beállításoktól függően, így ezek
explicit betöltésével (+use+) nem kell bajlódnod.
## Tesztelés
Sinatra teszteket bármely Rack alapú tesztelő könyvtárral vagy
keretrendszerrel készíthetsz. Mi a [Rack::Test](http://gitrdoc.com/brynary/rack-test)
könyvtárat ajánljuk:
```ruby
require 'my_sinatra_app'
require 'rack/test'
class MyAppTest < Test::Unit::TestCase
include Rack::Test::Methods
def app
Sinatra::Application
end
def test_my_default
get '/'
assert_equal 'Helló Világ!', last_response.body
end
def test_with_params
get '/meet', :name => 'Frici'
assert_equal 'Helló Frici!', last_response.body
end
def test_with_rack_env
get '/', {}, 'HTTP_USER_AGENT' => 'Songbird'
assert_equal "Songbird-öt használsz!", last_response.body
end
end
```
Megjegyzés: A beépített Sinatra::Test és Sinatra::TestHarness osztályok
a 0.9.2-es kiadástól kezdve elavultnak számítanak.
## Sinatra::Base - Middleware-ek, könyvtárak és moduláris alkalmazások
Az alkalmazást felső szinten építeni megfelelhet mondjuk egy kisebb
app esetén, ám kifejezetten károsnak bizonyulhat olyan komolyabb,
újra felhasználható komponensek készítésekor, mint például egy Rack
middleware, Rails metal, egyszerűbb kiszolgáló komponenssel bíró
könyvtárak vagy éppen Sinatra kiterjesztések. A felső szintű DSL
bepiszkítja az Objektum névteret, ráadásul kisalkalmazásokra szabott
beállításokat feltételez (így például egyetlen alkalmazásfájl,
`./public`
és `./views` könyvtár meglétét, naplózást, kivételkezelő oldalt stb.).
Itt jön a képbe a Sinatra::Base osztály:
```ruby
require 'sinatra/base'
class MyApp < Sinatra::Base
set :sessions, true
set :foo, 'bar'
get '/' do
'Helló Világ!'
end
end
```
A MyApp osztály immár önálló Rack komponensként, mondjuk Rack middleware-ként
vagy alkalmazásként, esetleg Rails metal-ként is tud működni. Közvetlenül
használhatod (`use`) vagy futtathatod (`run`) az osztályodat egy rackup
konfigurációs állományban (`config.ru`), vagy egy szerverkomponenst
tartalmazó könyvtár vezérlésekor:
```ruby
MyApp.run! :host => 'localhost', :port => 9090
```
A Sinatra::Base gyermekosztályaiban elérhető metódusok egyúttal a felső
szintű DSL-en keresztül is hozzáférhetők. A legtöbb felső szintű
alkalmazás átalakítható Sinatra::Base alapú komponensekké két lépésben:
* A fájlban nem a `sinatra`, hanem a `sinatra/base` osztályt kell
beimportálni, mert egyébként az összes Sinatra DSL metódus a fő
névtérbe kerül.
* Az alkalmazás útvonalait, hibakezelőit, szűrőit és beállításait
a Sinatra::Base osztály gyermekosztályaiban kell megadni.
A `Sinatra::Base` osztály igazából egy üres lap: a legtöbb funkció
alapból ki van kapcsolva, beleértve a beépített szervert is. A
beállításokkal és az egyes kapcsolók hatásával az
[Options and Configuration](http://sinatra.github.com/configuration.html) lap
foglalkozik.
Széljegyzet: A Sinatra felső szintű DSL-je egy egyszerű delegációs
rendszerre épül. A Sinatra::Application osztály - a Sinatra::Base egy
speciális osztályaként - fogadja az összes :get, :put, :post,
:delete, :before, :error, :not_found, :configure és :set üzenetet,
ami csak a felső szintre beérkezik. Érdemes utánanézned a kódban,
miképp [kerül be](http://github.com/sinatra/sinatra/blob/master/lib/sinatra/main.rb#L25)
a [Sinatra::Delegator mixin](http://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L1064)
a fő névtérbe.
## Parancssori lehetőségek
Sinatra alkalmazásokat közvetlenül futtathatunk:
```
ruby myapp.rb [-h] [-x] [-e ENVIRONMENT] [-p PORT] [-s HANDLER]
```
Az alábbi kapcsolókat ismeri fel a rendszer:
-h # segítség
-p # a port beállítása (alapértelmezés szerint ez a 4567-es)
-e # a környezet beállítása (alapértelmezés szerint ez a development)
-s # a rack szerver/handler beállítása (alapértelmezetten ez a thin)
-x # a mutex lock bekapcsolása (alapértelmezetten ki van kapcsolva)
## Fejlesztői változat
Ha a Sinatra legfrissebb, fejlesztői változatát szeretnéd használni,
készíts egy helyi másolatot és indítsd az alkalmazásodat úgy,
hogy a `sinatra/lib` könyvtár elérhető legyen a
`LOAD_PATH`-on:
```
cd myapp
git clone git://github.com/sinatra/sinatra.git
ruby -Isinatra/lib myapp.rb
```
De hozzá is adhatod a sinatra/lib könyvtárat a LOAD_PATH-hoz
az alkalmazásodban:
```ruby
$LOAD_PATH.unshift File.dirname(__FILE__) + '/sinatra/lib'
require 'rubygems'
require 'sinatra'
get '/about' do
"A következő változatot futtatom " + Sinatra::VERSION
end
```
A Sinatra frissítését később így végezheted el:
```
cd myproject/sinatra
git pull
```
## További információk
* [A projekt weboldala](http://sinatra.github.com/) - Kiegészítő dokumentáció,
hírek, hasznos linkek
* [Közreműködés](http://sinatra.github.com/contributing.html) - Hibát találtál?
Segítségre van szükséged? Foltot küldenél be?
* [Lighthouse](http://sinatra.lighthouseapp.com) - Hibakövetés és kiadások
* [Twitter](http://twitter.com/sinatra)
* [Levelezőlista](http://groups.google.com/group/sinatrarb)
* [IRC: #sinatra](irc://chat.freenode.net/#sinatra) a http://freenode.net címen
sinatra-1.4.3/test/ 0000755 0000041 0000041 00000000000 12161612727 014174 5 ustar www-data www-data sinatra-1.4.3/test/haml_test.rb 0000644 0000041 0000041 00000005645 12161612727 016513 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
begin
require 'haml'
class HAMLTest < Test::Unit::TestCase
def haml_app(&block)
mock_app do
set :views, File.dirname(__FILE__) + '/views'
get('/', &block)
end
get '/'
end
it 'renders inline HAML strings' do
haml_app { haml '%h1 Hiya' }
assert ok?
assert_equal "
Hiya
\n", body
end
it 'renders .haml files in views path' do
haml_app { haml :hello }
assert ok?
assert_equal "Hello From Haml
\n", body
end
it "renders with inline layouts" do
mock_app do
layout { %q(%h1= 'THIS. IS. ' + yield.upcase) }
get('/') { haml '%em Sparta' }
end
get '/'
assert ok?
assert_equal "THIS. IS. SPARTA
\n", body
end
it "renders with file layouts" do
haml_app { haml 'Hello World', :layout => :layout2 }
assert ok?
assert_equal "HAML Layout!
\nHello World
\n", body
end
it "raises error if template not found" do
mock_app { get('/') { haml :no_such_template } }
assert_raise(Errno::ENOENT) { get('/') }
end
it "passes HAML options to the Haml engine" do
mock_app {
get('/') { haml "!!!\n%h1 Hello World", :format => :html5 }
}
get '/'
assert ok?
assert_equal "\nHello World
\n", body
end
it "passes default HAML options to the Haml engine" do
mock_app do
set :haml, {:format => :html5}
get('/') { haml "!!!\n%h1 Hello World" }
end
get '/'
assert ok?
assert_equal "\nHello World
\n", body
end
it "merges the default HAML options with the overrides and passes them to the Haml engine" do
mock_app do
set :haml, {:format => :html5, :attr_wrapper => '"'} # default HAML attr are
get('/') { haml "!!!\n%h1{:class => :header} Hello World" }
get('/html4') {
haml "!!!\n%h1{:class => 'header'} Hello World", :format => :html4
}
end
get '/'
assert ok?
assert_equal "\n\n", body
get '/html4'
assert ok?
assert_match(/^ { :foo => 'bar' }}
assert_equal "bar\n", body
end
it "can render truly nested layouts by accepting a layout and a block with the contents" do
mock_app do
template(:main_outer_layout) { "%h1 Title\n= yield" }
template(:an_inner_layout) { "%h2 Subtitle\n= yield" }
template(:a_page) { "%p Contents." }
get('/') do
haml :main_outer_layout, :layout => false do
haml :an_inner_layout do
haml :a_page
end
end
end
end
get '/'
assert ok?
assert_body "Title
\nSubtitle
\nContents.
\n"
end
end
rescue LoadError
warn "#{$!.to_s}: skipping haml tests"
end
sinatra-1.4.3/test/coffee_test.rb 0000644 0000041 0000041 00000004216 12161612727 017012 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
begin
require 'coffee-script'
require 'execjs'
begin
ExecJS.compile '1'
rescue Exception
raise LoadError, 'unable to execute JavaScript'
end
class CoffeeTest < Test::Unit::TestCase
def coffee_app(options = {}, &block)
mock_app do
set :views, File.dirname(__FILE__) + '/views'
set(options)
get('/', &block)
end
get '/'
end
it 'renders inline Coffee strings' do
coffee_app { coffee "alert 'Aye!'\n" }
assert ok?
assert body.include?("alert('Aye!');")
end
it 'defaults content type to javascript' do
coffee_app { coffee "alert 'Aye!'\n" }
assert ok?
assert_equal "application/javascript;charset=utf-8", response['Content-Type']
end
it 'defaults allows setting content type per route' do
coffee_app do
content_type :html
coffee "alert 'Aye!'\n"
end
assert ok?
assert_equal "text/html;charset=utf-8", response['Content-Type']
end
it 'defaults allows setting content type globally' do
coffee_app(:coffee => { :content_type => 'html' }) do
coffee "alert 'Aye!'\n"
end
assert ok?
assert_equal "text/html;charset=utf-8", response['Content-Type']
end
it 'renders .coffee files in views path' do
coffee_app { coffee :hello }
assert ok?
assert_include body, "alert(\"Aye!\");"
end
it 'ignores the layout option' do
coffee_app { coffee :hello, :layout => :layout2 }
assert ok?
assert_include body, "alert(\"Aye!\");"
end
it "raises error if template not found" do
mock_app {
get('/') { coffee :no_such_template }
}
assert_raise(Errno::ENOENT) { get('/') }
end
it "passes coffee options to the coffee engine" do
coffee_app { coffee "alert 'Aye!'\n", :no_wrap => true }
assert ok?
assert_body "alert('Aye!');"
end
it "passes default coffee options to the coffee engine" do
mock_app do
set :coffee, :no_wrap => true # default coffee style is :nested
get('/') { coffee "alert 'Aye!'\n" }
end
get '/'
assert ok?
assert_body "alert('Aye!');"
end
end
rescue LoadError
warn "#{$!.to_s}: skipping coffee tests"
end
sinatra-1.4.3/test/radius_test.rb 0000644 0000041 0000041 00000002543 12161612727 017053 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
begin
require 'radius'
class RadiusTest < Test::Unit::TestCase
def radius_app(&block)
mock_app do
set :views, File.dirname(__FILE__) + '/views'
get('/', &block)
end
get '/'
end
it 'renders inline radius strings' do
radius_app { radius 'Hiya
' }
assert ok?
assert_equal "Hiya
", body
end
it 'renders .radius files in views path' do
radius_app { radius :hello }
assert ok?
assert_equal "Hello From Radius
\n", body
end
it "renders with inline layouts" do
mock_app do
layout { "THIS. IS.
" }
get('/') { radius 'SPARTA' }
end
get '/'
assert ok?
assert_equal "THIS. IS. SPARTA
", body
end
it "renders with file layouts" do
radius_app { radius 'Hello World', :layout => :layout2 }
assert ok?
assert_equal "Radius Layout!
\nHello World
\n", body
end
it "raises error if template not found" do
mock_app { get('/') { radius :no_such_template } }
assert_raise(Errno::ENOENT) { get('/') }
end
it "allows passing locals" do
radius_app {
radius '', :locals => { :value => 'foo' }
}
assert ok?
assert_equal 'foo', body
end
end
rescue LoadError
warn "#{$!.to_s}: skipping radius tests"
end
sinatra-1.4.3/test/request_test.rb 0000644 0000041 0000041 00000005013 12161612727 017247 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
require 'stringio'
class RequestTest < Test::Unit::TestCase
it 'responds to #user_agent' do
request = Sinatra::Request.new({'HTTP_USER_AGENT' => 'Test'})
assert request.respond_to?(:user_agent)
assert_equal 'Test', request.user_agent
end
it 'parses POST params when Content-Type is form-dataish' do
request = Sinatra::Request.new(
'REQUEST_METHOD' => 'PUT',
'CONTENT_TYPE' => 'application/x-www-form-urlencoded',
'rack.input' => StringIO.new('foo=bar')
)
assert_equal 'bar', request.params['foo']
end
it 'is secure when the url scheme is https' do
request = Sinatra::Request.new('rack.url_scheme' => 'https')
assert request.secure?
end
it 'is not secure when the url scheme is http' do
request = Sinatra::Request.new('rack.url_scheme' => 'http')
assert !request.secure?
end
it 'respects X-Forwarded-Proto header for proxied SSL' do
request = Sinatra::Request.new('HTTP_X_FORWARDED_PROTO' => 'https')
assert request.secure?
end
it 'is possible to marshal params' do
request = Sinatra::Request.new(
'REQUEST_METHOD' => 'PUT',
'CONTENT_TYPE' => 'application/x-www-form-urlencoded',
'rack.input' => StringIO.new('foo=bar')
)
Sinatra::Base.new!.send(:indifferent_hash).replace(request.params)
dumped = Marshal.dump(request.params)
assert_equal 'bar', Marshal.load(dumped)['foo']
end
it "exposes the preferred type's parameters" do
request = Sinatra::Request.new(
'HTTP_ACCEPT' => 'image/jpeg; compress=0.25'
)
assert_equal({ 'compress' => '0.25' }, request.preferred_type.params)
end
it "makes accept types behave like strings" do
request = Sinatra::Request.new('HTTP_ACCEPT' => 'image/jpeg; compress=0.25')
assert request.accept?('image/jpeg')
assert_equal 'image/jpeg', request.preferred_type.to_s
assert_equal 'image/jpeg', request.preferred_type.to_str
assert_equal 'image', request.preferred_type.split('/').first
String.instance_methods.each do |method|
next unless "".respond_to? method
assert request.preferred_type.respond_to?(method), "responds to #{method}"
end
end
it "properly decodes MIME type parameters" do
request = Sinatra::Request.new(
'HTTP_ACCEPT' => 'image/jpeg;unquoted=0.25;quoted="0.25";chartest="\";,\x"'
)
expected = { 'unquoted' => '0.25', 'quoted' => '0.25', 'chartest' => '";,x' }
assert_equal(expected, request.preferred_type.params)
end
end
sinatra-1.4.3/test/encoding_test.rb 0000644 0000041 0000041 00000001161 12161612727 017345 0 ustar www-data www-data # encoding: UTF-8
require File.expand_path('../helper', __FILE__)
require 'erb'
class BaseTest < Test::Unit::TestCase
setup do
@base = Sinatra.new(Sinatra::Base)
@base.set :views, File.dirname(__FILE__) + "/views"
end
it 'allows unicode strings in ascii templates per default (1.9)' do
next unless defined? Encoding
@base.new!.erb(File.read(@base.views + "/ascii.erb").encode("ASCII"), {}, :value => "åkej")
end
it 'allows ascii strings in unicode templates per default (1.9)' do
next unless defined? Encoding
@base.new!.erb(:utf8, {}, :value => "Some Lyrics".encode("ASCII"))
end
end
sinatra-1.4.3/test/integration_helper.rb 0000644 0000041 0000041 00000013072 12161612727 020406 0 ustar www-data www-data require 'sinatra/base'
require 'rbconfig'
require 'open-uri'
require 'net/http'
require 'timeout'
module IntegrationHelper
class BaseServer
extend Enumerable
attr_accessor :server, :port, :pipe
alias name server
def self.all
@all ||= []
end
def self.each(&block)
all.each(&block)
end
def self.run(server, port)
new(server, port).run
end
def app_file
File.expand_path('../integration/app.rb', __FILE__)
end
def environment
"development"
end
def initialize(server, port)
@installed, @pipe, @server, @port = nil, nil, server, port
Server.all << self
end
def run
return unless installed?
kill
@log = ""
@pipe = IO.popen(command)
@started = Time.now
warn "#{server} up and running on port #{port}" if ping
at_exit { kill }
end
def ping(timeout = 30)
loop do
return if alive?
if Time.now - @started > timeout
$stderr.puts command, log
fail "timeout"
else
sleep 0.1
end
end
end
def alive?
3.times { get('/ping') }
true
rescue Errno::ECONNREFUSED, Errno::ECONNRESET, EOFError, SystemCallError, OpenURI::HTTPError, Timeout::Error
false
end
def get_stream(url = "/stream", &block)
Net::HTTP.start '127.0.0.1', port do |http|
request = Net::HTTP::Get.new url
http.request request do |response|
response.read_body(&block)
end
end
end
def get(url)
Timeout.timeout(1) { open("http://127.0.0.1:#{port}#{url}").read }
end
def log
@log ||= ""
loop { @log << @pipe.read_nonblock(1) }
rescue Exception
@log
end
def installed?
return @installed unless @installed.nil?
s = server == 'HTTP' ? 'net/http/server' : server
require s
@installed = true
rescue LoadError
warn "#{server} is not installed, skipping integration tests"
@installed = false
end
def command
@command ||= begin
cmd = ["RACK_ENV=#{environment}", "exec"]
if RbConfig.respond_to? :ruby
cmd << RbConfig.ruby.inspect
else
file, dir = RbConfig::CONFIG.values_at('ruby_install_name', 'bindir')
cmd << File.expand_path(file, dir).inspect
end
cmd << "-w" unless thin? || net_http_server?
cmd << "-I" << File.expand_path('../../lib', __FILE__).inspect
cmd << app_file.inspect << '-s' << server << '-o' << '127.0.0.1' << '-p' << port
cmd << "-e" << environment.to_s << '2>&1'
cmd.join " "
end
end
def kill
return unless pipe
Process.kill("KILL", pipe.pid)
rescue NotImplementedError
system "kill -9 #{pipe.pid}"
rescue Errno::ESRCH
end
def webrick?
name.to_s == "webrick"
end
def thin?
name.to_s == "thin"
end
def puma?
name.to_s == "puma"
end
def trinidad?
name.to_s == "trinidad"
end
def net_http_server?
name.to_s == 'HTTP'
end
def warnings
log.scan(%r[(?:\(eval|lib/sinatra).*warning:.*$])
end
def run_test(target, &block)
retries ||= 3
target.server = self
run unless alive?
target.instance_eval(&block)
rescue Exception => error
retries -= 1
kill
retries < 0 ? retry : raise(error)
end
end
if RUBY_ENGINE == "jruby"
class JRubyServer < BaseServer
def start_vm
require 'java'
# Create a new container, set load paths and env
# SINGLETHREAD means create a new runtime
vm = org.jruby.embed.ScriptingContainer.new(org.jruby.embed.LocalContextScope::SINGLETHREAD)
vm.load_paths = [File.expand_path('../../lib', __FILE__)]
vm.environment = ENV.merge('RACK_ENV' => environment.to_s)
# This ensures processing of RUBYOPT which activates Bundler
vm.provider.ruby_instance_config.process_arguments []
vm.argv = ['-s', server.to_s, '-o', '127.0.0.1', '-p', port.to_s, '-e', environment.to_s]
# Set stdout/stderr so we can retrieve log
@pipe = java.io.ByteArrayOutputStream.new
vm.output = java.io.PrintStream.new(@pipe)
vm.error = java.io.PrintStream.new(@pipe)
Thread.new do
# Hack to ensure that Kernel#caller has the same info as
# when run from command-line, for Sinatra::Application.app_file.
# Also, line numbers are zero-based in JRuby's parser
vm.provider.runtime.current_context.set_file_and_line(app_file, 0)
# Run the app
vm.run_scriptlet org.jruby.embed.PathType::ABSOLUTE, app_file
# terminate launches at_exit hooks which start server
vm.terminate
end
end
def run
return unless installed?
kill
@thread = start_vm
@started = Time.now
warn "#{server} up and running on port #{port}" if ping
at_exit { kill }
end
def log
String.from_java_bytes @pipe.to_byte_array
end
def kill
@thread.kill if @thread
@thread = nil
end
end
Server = JRubyServer
else
Server = BaseServer
end
def it(message, &block)
Server.each do |server|
next unless server.installed?
super("with #{server.name}: #{message}") { server.run_test(self, &block) }
end
end
def self.extend_object(obj)
super
base_port = 5000 + Process.pid % 100
Sinatra::Base.server.each_with_index do |server, index|
Server.run(server, 5000+index)
end
end
end
sinatra-1.4.3/test/delegator_test.rb 0000644 0000041 0000041 00000007431 12161612727 017533 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
class DelegatorTest < Test::Unit::TestCase
class Mirror
attr_reader :last_call
def method_missing(*a, &b)
@last_call = [*a.map(&:to_s)]
@last_call << b if b
end
end
def self.delegates(name)
it "delegates #{name}" do
m = mirror { send name }
assert_equal [name.to_s], m.last_call
end
it "delegates #{name} with arguments" do
m = mirror { send name, "foo", "bar" }
assert_equal [name.to_s, "foo", "bar"], m.last_call
end
it "delegates #{name} with block" do
block = proc { }
m = mirror { send(name, &block) }
assert_equal [name.to_s, block], m.last_call
end
end
setup do
@target_was = Sinatra::Delegator.target
end
def teardown
Sinatra::Delegator.target = @target_was
end
def delegation_app(&block)
mock_app { Sinatra::Delegator.target = self }
delegate(&block)
end
def mirror(&block)
mirror = Mirror.new
Sinatra::Delegator.target = mirror
delegate(&block)
end
def delegate(&block)
assert Sinatra::Delegator.target != Sinatra::Application
Object.new.extend(Sinatra::Delegator).instance_eval(&block) if block
Sinatra::Delegator.target
end
def target
Sinatra::Delegator.target
end
it 'defaults to Sinatra::Application as target' do
assert_equal Sinatra::Application, Sinatra::Delegator.target
end
%w[get put post delete options patch link unlink].each do |verb|
it "delegates #{verb} correctly" do
delegation_app do
send(verb, '/hello') { 'Hello World' }
end
request = Rack::MockRequest.new(@app)
response = request.request(verb.upcase, '/hello', {})
assert response.ok?
assert_equal 'Hello World', response.body
end
end
it "delegates head correctly" do
delegation_app do
head '/hello' do
response['X-Hello'] = 'World!'
'remove me'
end
end
request = Rack::MockRequest.new(@app)
response = request.request('HEAD', '/hello', {})
assert response.ok?
assert_equal 'World!', response['X-Hello']
assert_equal '', response.body
end
it "registers extensions with the delegation target" do
app, mixin = mirror, Module.new
Sinatra.register mixin
assert_equal ["register", mixin.to_s], app.last_call
end
it "registers helpers with the delegation target" do
app, mixin = mirror, Module.new
Sinatra.helpers mixin
assert_equal ["helpers", mixin.to_s], app.last_call
end
it "registers middleware with the delegation target" do
app, mixin = mirror, Module.new
Sinatra.use mixin
assert_equal ["use", mixin.to_s], app.last_call
end
it "should work with method_missing proxies for options" do
mixin = Module.new do
def respond_to?(method, *)
method.to_sym == :options or super
end
def method_missing(method, *args, &block)
return super unless method.to_sym == :options
{:some => :option}
end
end
value = nil
mirror do
extend mixin
value = options
end
assert_equal({:some => :option}, value)
end
it "delegates crazy method names" do
Sinatra::Delegator.delegate "foo:bar:"
method = mirror { send "foo:bar:" }.last_call.first
assert_equal "foo:bar:", method
end
delegates 'get'
delegates 'patch'
delegates 'put'
delegates 'post'
delegates 'delete'
delegates 'head'
delegates 'options'
delegates 'template'
delegates 'layout'
delegates 'before'
delegates 'after'
delegates 'error'
delegates 'not_found'
delegates 'configure'
delegates 'set'
delegates 'mime_type'
delegates 'enable'
delegates 'disable'
delegates 'use'
delegates 'development?'
delegates 'test?'
delegates 'production?'
delegates 'helpers'
delegates 'settings'
end
sinatra-1.4.3/test/nokogiri_test.rb 0000644 0000041 0000041 00000003207 12161612727 017403 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
begin
require 'nokogiri'
class NokogiriTest < Test::Unit::TestCase
def nokogiri_app(&block)
mock_app do
set :views, File.dirname(__FILE__) + '/views'
get('/', &block)
end
get '/'
end
it 'renders inline Nokogiri strings' do
nokogiri_app { nokogiri 'xml' }
assert ok?
assert_body %(\n)
end
it 'renders inline blocks' do
nokogiri_app do
@name = "Frank & Mary"
nokogiri { |xml| xml.couple @name }
end
assert ok?
assert_body %(\nFrank & Mary\n)
end
it 'renders .nokogiri files in views path' do
nokogiri_app do
@name = "Blue"
nokogiri :hello
end
assert ok?
assert_body "\nYou're my boy, Blue!\n"
end
it "renders with inline layouts" do
next if Tilt::VERSION <= "1.1"
mock_app do
layout { %(xml.layout { xml << yield }) }
get('/') { nokogiri %(xml.em 'Hello World') }
end
get '/'
assert ok?
assert_body %(\n\n Hello World\n\n)
end
it "renders with file layouts" do
next if Tilt::VERSION <= "1.1"
nokogiri_app {
nokogiri %(xml.em 'Hello World'), :layout => :layout2
}
assert ok?
assert_body %(\n\n Hello World\n\n)
end
it "raises error if template not found" do
mock_app { get('/') { nokogiri :no_such_template } }
assert_raise(Errno::ENOENT) { get('/') }
end
end
rescue LoadError
warn "#{$!.to_s}: skipping nokogiri tests"
end
sinatra-1.4.3/test/wlang_test.rb 0000644 0000041 0000041 00000003671 12161612727 016677 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
begin
require 'wlang'
class WLangTest < Test::Unit::TestCase
def engine
Tilt::WLangTemplate
end
def wlang_app(&block)
mock_app {
set :views, File.dirname(__FILE__) + '/views'
get '/', &block
}
get '/'
end
it 'uses the correct engine' do
assert_equal engine, Tilt[:wlang]
end
it 'renders .wlang files in views path' do
wlang_app { wlang :hello }
assert ok?
assert_equal "Hello from wlang!\n", body
end
it 'renders in the app instance scope' do
mock_app do
helpers do
def who; "world"; end
end
get('/') { wlang 'Hello +{who}!' }
end
get '/'
assert ok?
assert_equal 'Hello world!', body
end
it 'takes a :locals option' do
wlang_app do
locals = {:foo => 'Bar'}
wlang 'Hello ${foo}!', :locals => locals
end
assert ok?
assert_equal 'Hello Bar!', body
end
it "renders with inline layouts" do
mock_app do
layout { 'THIS. IS. +{yield.upcase}!' }
get('/') { wlang 'Sparta' }
end
get '/'
assert ok?
assert_equal 'THIS. IS. SPARTA!', body
end
it "renders with file layouts" do
wlang_app { wlang 'Hello World', :layout => :layout2 }
assert ok?
assert_body "WLang Layout!\nHello World"
end
it "can rendered truly nested layouts by accepting a layout and a block with the contents" do
mock_app do
template(:main_outer_layout) { "Title
\n>{ yield }" }
template(:an_inner_layout) { "Subtitle
\n>{ yield }" }
template(:a_page) { "Contents.
\n" }
get('/') do
wlang :main_outer_layout, :layout => false do
wlang :an_inner_layout do
wlang :a_page
end
end
end
end
get '/'
assert ok?
assert_body "Title
\nSubtitle
\nContents.
\n"
end
end
rescue LoadError
warn "#{$!.to_s}: skipping wlang tests"
end
sinatra-1.4.3/test/server_test.rb 0000644 0000041 0000041 00000001645 12161612727 017074 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
require 'stringio'
module Rack::Handler
class Mock
extend Test::Unit::Assertions
def self.run(app, options={})
assert(app < Sinatra::Base)
assert_equal 9001, options[:Port]
assert_equal 'foo.local', options[:Host]
yield new
end
def stop
end
end
register 'mock', 'Rack::Handler::Mock'
end
class ServerTest < Test::Unit::TestCase
setup do
mock_app do
set :server, 'mock'
set :bind, 'foo.local'
set :port, 9001
end
$stderr = StringIO.new
end
def teardown
$stderr = STDERR
end
it "locates the appropriate Rack handler and calls ::run" do
@app.run!
end
it "sets options on the app before running" do
@app.run! :sessions => true
assert @app.sessions?
end
it "falls back on the next server handler when not found" do
@app.run! :server => %w[foo bar mock]
end
end
sinatra-1.4.3/test/filter_test.rb 0000644 0000041 0000041 00000025545 12161612727 017060 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
class BeforeFilterTest < Test::Unit::TestCase
it "executes filters in the order defined" do
count = 0
mock_app do
get('/') { 'Hello World' }
before do
assert_equal 0, count
count = 1
end
before do
assert_equal 1, count
count = 2
end
end
get '/'
assert ok?
assert_equal 2, count
assert_equal 'Hello World', body
end
it "can modify the request" do
mock_app do
get('/foo') { 'foo' }
get('/bar') { 'bar' }
before { request.path_info = '/bar' }
end
get '/foo'
assert ok?
assert_equal 'bar', body
end
it "can modify instance variables available to routes" do
mock_app do
before { @foo = 'bar' }
get('/foo') { @foo }
end
get '/foo'
assert ok?
assert_equal 'bar', body
end
it "allows redirects" do
mock_app do
before { redirect '/bar' }
get('/foo') do
fail 'before block should have halted processing'
'ORLY?!'
end
end
get '/foo'
assert redirect?
assert_equal 'http://example.org/bar', response['Location']
assert_equal '', body
end
it "does not modify the response with its return value" do
mock_app do
before { 'Hello World!' }
get('/foo') do
assert_equal [], response.body
'cool'
end
end
get '/foo'
assert ok?
assert_equal 'cool', body
end
it "does modify the response with halt" do
mock_app do
before { halt 302, 'Hi' }
get '/foo' do
"should not happen"
end
end
get '/foo'
assert_equal 302, response.status
assert_equal 'Hi', body
end
it "gives you access to params" do
mock_app do
before { @foo = params['foo'] }
get('/foo') { @foo }
end
get '/foo?foo=cool'
assert ok?
assert_equal 'cool', body
end
it "properly unescapes parameters" do
mock_app do
before { @foo = params['foo'] }
get('/foo') { @foo }
end
get '/foo?foo=bar%3Abaz%2Fbend'
assert ok?
assert_equal 'bar:baz/bend', body
end
it "runs filters defined in superclasses" do
base = Class.new(Sinatra::Base)
base.before { @foo = 'hello from superclass' }
mock_app(base) { get('/foo') { @foo } }
get '/foo'
assert_equal 'hello from superclass', body
end
it 'does not run before filter when serving static files' do
ran_filter = false
mock_app do
before { ran_filter = true }
set :static, true
set :public_folder, File.dirname(__FILE__)
end
get "/#{File.basename(__FILE__)}"
assert ok?
assert_equal File.read(__FILE__), body
assert !ran_filter
end
it 'takes an optional route pattern' do
ran_filter = false
mock_app do
before("/b*") { ran_filter = true }
get('/foo') { }
get('/bar') { }
end
get '/foo'
assert !ran_filter
get '/bar'
assert ran_filter
end
it 'generates block arguments from route pattern' do
subpath = nil
mock_app do
before("/foo/:sub") { |s| subpath = s }
get('/foo/*') { }
end
get '/foo/bar'
assert_equal subpath, 'bar'
end
it 'can catch exceptions in before filters and handle them properly' do
doodle = ''
mock_app do
before do
doodle += 'This begins'
raise StandardError, "before"
end
get "/" do
doodle = 'and runs'
end
error 500 do
"Error handled #{env['sinatra.error'].message}"
end
end
doodle = ''
get '/'
assert_equal 'Error handled before', body
assert_equal 'This begins', doodle
end
end
class AfterFilterTest < Test::Unit::TestCase
it "executes before and after filters in correct order" do
invoked = 0
mock_app do
before { invoked = 2 }
get('/') { invoked += 2; 'hello' }
after { invoked *= 2 }
end
get '/'
assert ok?
assert_equal 8, invoked
end
it "executes filters in the order defined" do
count = 0
mock_app do
get('/') { 'Hello World' }
after do
assert_equal 0, count
count = 1
end
after do
assert_equal 1, count
count = 2
end
end
get '/'
assert ok?
assert_equal 2, count
assert_equal 'Hello World', body
end
it "allows redirects" do
mock_app do
get('/foo') { 'ORLY' }
after { redirect '/bar' }
end
get '/foo'
assert redirect?
assert_equal 'http://example.org/bar', response['Location']
assert_equal '', body
end
it "does not modify the response with its return value" do
mock_app do
get('/foo') { 'cool' }
after { 'Hello World!' }
end
get '/foo'
assert ok?
assert_equal 'cool', body
end
it "does modify the response with halt" do
mock_app do
get '/foo' do
"should not be returned"
end
after { halt 302, 'Hi' }
end
get '/foo'
assert_equal 302, response.status
assert_equal 'Hi', body
end
it "runs filters defined in superclasses" do
count = 2
base = Class.new(Sinatra::Base)
base.after { count *= 2 }
mock_app(base) do
get('/foo') do
count += 2
"ok"
end
end
get '/foo'
assert_equal 8, count
end
it 'does not run after filter when serving static files' do
ran_filter = false
mock_app do
after { ran_filter = true }
set :static, true
set :public_folder, File.dirname(__FILE__)
end
get "/#{File.basename(__FILE__)}"
assert ok?
assert_equal File.read(__FILE__), body
assert !ran_filter
end
it 'takes an optional route pattern' do
ran_filter = false
mock_app do
after("/b*") { ran_filter = true }
get('/foo') { }
get('/bar') { }
end
get '/foo'
assert !ran_filter
get '/bar'
assert ran_filter
end
it 'changes to path_info from a pattern matching before filter are respected when routing' do
mock_app do
before('/foo') { request.path_info = '/bar' }
get('/bar') { 'blah' }
end
get '/foo'
assert ok?
assert_equal 'blah', body
end
it 'generates block arguments from route pattern' do
subpath = nil
mock_app do
after("/foo/:sub") { |s| subpath = s }
get('/foo/*') { }
end
get '/foo/bar'
assert_equal subpath, 'bar'
end
it 'is possible to access url params from the route param' do
ran = false
mock_app do
get('/foo/*') { }
before('/foo/:sub') do
assert_equal params[:sub], 'bar'
ran = true
end
end
get '/foo/bar'
assert ran
end
it 'is possible to apply host_name conditions to before filters with no path' do
ran = false
mock_app do
before(:host_name => 'example.com') { ran = true }
get('/') { 'welcome' }
end
get('/', {}, { 'HTTP_HOST' => 'example.org' })
assert !ran
get('/', {}, { 'HTTP_HOST' => 'example.com' })
assert ran
end
it 'is possible to apply host_name conditions to before filters with a path' do
ran = false
mock_app do
before('/foo', :host_name => 'example.com') { ran = true }
get('/') { 'welcome' }
end
get('/', {}, { 'HTTP_HOST' => 'example.com' })
assert !ran
get('/foo', {}, { 'HTTP_HOST' => 'example.org' })
assert !ran
get('/foo', {}, { 'HTTP_HOST' => 'example.com' })
assert ran
end
it 'is possible to apply host_name conditions to after filters with no path' do
ran = false
mock_app do
after(:host_name => 'example.com') { ran = true }
get('/') { 'welcome' }
end
get('/', {}, { 'HTTP_HOST' => 'example.org' })
assert !ran
get('/', {}, { 'HTTP_HOST' => 'example.com' })
assert ran
end
it 'is possible to apply host_name conditions to after filters with a path' do
ran = false
mock_app do
after('/foo', :host_name => 'example.com') { ran = true }
get('/') { 'welcome' }
end
get('/', {}, { 'HTTP_HOST' => 'example.com' })
assert !ran
get('/foo', {}, { 'HTTP_HOST' => 'example.org' })
assert !ran
get('/foo', {}, { 'HTTP_HOST' => 'example.com' })
assert ran
end
it 'is possible to apply user_agent conditions to before filters with no path' do
ran = false
mock_app do
before(:user_agent => /foo/) { ran = true }
get('/') { 'welcome' }
end
get('/', {}, { 'HTTP_USER_AGENT' => 'bar' })
assert !ran
get('/', {}, { 'HTTP_USER_AGENT' => 'foo' })
assert ran
end
it 'is possible to apply user_agent conditions to before filters with a path' do
ran = false
mock_app do
before('/foo', :user_agent => /foo/) { ran = true }
get('/') { 'welcome' }
end
get('/', {}, { 'HTTP_USER_AGENT' => 'foo' })
assert !ran
get('/foo', {}, { 'HTTP_USER_AGENT' => 'bar' })
assert !ran
get('/foo', {}, { 'HTTP_USER_AGENT' => 'foo' })
assert ran
end
it 'can add params' do
mock_app do
before { params['foo'] = 'bar' }
get('/') { params['foo'] }
end
get '/'
assert_body 'bar'
end
it 'can remove params' do
mock_app do
before { params.delete('foo') }
get('/') { params['foo'].to_s }
end
get '/?foo=bar'
assert_body ''
end
it 'is possible to apply user_agent conditions to after filters with no path' do
ran = false
mock_app do
after(:user_agent => /foo/) { ran = true }
get('/') { 'welcome' }
end
get('/', {}, { 'HTTP_USER_AGENT' => 'bar' })
assert !ran
get('/', {}, { 'HTTP_USER_AGENT' => 'foo' })
assert ran
end
it 'is possible to apply user_agent conditions to after filters with a path' do
ran = false
mock_app do
after('/foo', :user_agent => /foo/) { ran = true }
get('/') { 'welcome' }
end
get('/', {}, { 'HTTP_USER_AGENT' => 'foo' })
assert !ran
get('/foo', {}, { 'HTTP_USER_AGENT' => 'bar' })
assert !ran
get('/foo', {}, { 'HTTP_USER_AGENT' => 'foo' })
assert ran
end
it 'only triggeres provides condition if conforms with current Content-Type' do
mock_app do
before(:provides => :txt) { @type = 'txt' }
before(:provides => :html) { @type = 'html' }
get('/') { @type }
end
get('/', {}, { 'HTTP_ACCEPT' => '*/*' })
assert_body 'txt'
end
it 'can catch exceptions in after filters and handle them properly' do
doodle = ''
mock_app do
after do
doodle += ' and after'
raise StandardError, "after"
end
get "/foo" do
doodle = 'Been now'
raise StandardError, "now"
end
get "/" do
doodle = 'Been now'
end
error 500 do
"Error handled #{env['sinatra.error'].message}"
end
end
get '/foo'
assert_equal 'Error handled now', body
assert_equal 'Been now and after', doodle
doodle = ''
get '/'
assert_equal 'Error handled after', body
assert_equal 'Been now and after', doodle
end
end
sinatra-1.4.3/test/scss_test.rb 0000644 0000041 0000041 00000004610 12161612727 016534 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
begin
raise LoadError, 'sass not supported on Ruby 2.0' if RUBY_VERSION >= '2.0'
require 'sass'
class ScssTest < Test::Unit::TestCase
def scss_app(options = {}, &block)
mock_app do
set :views, File.dirname(__FILE__) + '/views'
set options
get('/', &block)
end
get '/'
end
it 'renders inline Scss strings' do
scss_app { scss "#scss {\n background-color: white; }\n" }
assert ok?
assert_equal "#scss {\n background-color: white; }\n", body
end
it 'defaults content type to css' do
scss_app { scss "#scss {\n background-color: white; }\n" }
assert ok?
assert_equal "text/css;charset=utf-8", response['Content-Type']
end
it 'defaults allows setting content type per route' do
scss_app do
content_type :html
scss "#scss {\n background-color: white; }\n"
end
assert ok?
assert_equal "text/html;charset=utf-8", response['Content-Type']
end
it 'defaults allows setting content type globally' do
scss_app(:scss => { :content_type => 'html' }) {
scss "#scss {\n background-color: white; }\n"
}
assert ok?
assert_equal "text/html;charset=utf-8", response['Content-Type']
end
it 'renders .scss files in views path' do
scss_app { scss :hello }
assert ok?
assert_equal "#scss {\n background-color: white; }\n", body
end
it 'ignores the layout option' do
scss_app { scss :hello, :layout => :layout2 }
assert ok?
assert_equal "#scss {\n background-color: white; }\n", body
end
it "raises error if template not found" do
mock_app { get('/') { scss(:no_such_template) } }
assert_raise(Errno::ENOENT) { get('/') }
end
it "passes scss options to the scss engine" do
scss_app do
scss(
"#scss {\n background-color: white;\n color: black\n}",
:style => :compact
)
end
assert ok?
assert_equal "#scss { background-color: white; color: black; }\n", body
end
it "passes default scss options to the scss engine" do
mock_app do
set :scss, {:style => :compact} # default scss style is :nested
get('/') {
scss("#scss {\n background-color: white;\n color: black;\n}")
}
end
get '/'
assert ok?
assert_equal "#scss { background-color: white; color: black; }\n", body
end
end
rescue LoadError
warn "#{$!.to_s}: skipping scss tests"
end
sinatra-1.4.3/test/base_test.rb 0000644 0000041 0000041 00000011554 12161612727 016500 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
class BaseTest < Test::Unit::TestCase
def test_default
assert true
end
describe 'Sinatra::Base subclasses' do
class TestApp < Sinatra::Base
get('/') { 'Hello World' }
end
it 'include Rack::Utils' do
assert TestApp.included_modules.include?(Rack::Utils)
end
it 'processes requests with #call' do
assert TestApp.respond_to?(:call)
request = Rack::MockRequest.new(TestApp)
response = request.get('/')
assert response.ok?
assert_equal 'Hello World', response.body
end
class TestApp < Sinatra::Base
get '/state' do
@foo ||= "new"
body = "Foo: #{@foo}"
@foo = 'discard'
body
end
end
it 'does not maintain state between requests' do
request = Rack::MockRequest.new(TestApp)
2.times do
response = request.get('/state')
assert response.ok?
assert_equal 'Foo: new', response.body
end
end
it "passes the subclass to configure blocks" do
ref = nil
TestApp.configure { |app| ref = app }
assert_equal TestApp, ref
end
it "allows the configure block arg to be omitted and does not change context" do
context = nil
TestApp.configure { context = self }
assert_equal self, context
end
end
describe "Sinatra::Base#new" do
it 'returns a wrapper' do
assert_equal Sinatra::Wrapper, Sinatra::Base.new.class
end
it 'implements a nice inspect' do
assert_equal '#', Sinatra::Base.new.inspect
end
it 'exposes settings' do
assert_equal Sinatra::Base.settings, Sinatra::Base.new.settings
end
it 'exposes helpers' do
assert_equal 'image/jpeg', Sinatra::Base.new.helpers.mime_type(:jpg)
end
end
describe "Sinatra::Base as Rack middleware" do
app = lambda { |env|
headers = {'X-Downstream' => 'true'}
headers['X-Route-Missing'] = env['sinatra.route-missing'] || ''
[210, headers, ['Hello from downstream']] }
class TestMiddleware < Sinatra::Base
end
it 'creates a middleware that responds to #call with .new' do
middleware = TestMiddleware.new(app)
assert middleware.respond_to?(:call)
end
it 'exposes the downstream app' do
middleware = TestMiddleware.new!(app)
assert_same app, middleware.app
end
class TestMiddleware < Sinatra::Base
def route_missing
env['sinatra.route-missing'] = '1'
super
end
get('/') { 'Hello from middleware' }
end
middleware = TestMiddleware.new(app)
request = Rack::MockRequest.new(middleware)
it 'intercepts requests' do
response = request.get('/')
assert response.ok?
assert_equal 'Hello from middleware', response.body
end
it 'automatically forwards requests downstream when no matching route found' do
response = request.get('/missing')
assert_equal 210, response.status
assert_equal 'Hello from downstream', response.body
end
it 'calls #route_missing before forwarding downstream' do
response = request.get('/missing')
assert_equal '1', response['X-Route-Missing']
end
class TestMiddleware < Sinatra::Base
get('/low-level-forward') { app.call(env) }
end
it 'can call the downstream app directly and return result' do
response = request.get('/low-level-forward')
assert_equal 210, response.status
assert_equal 'true', response['X-Downstream']
assert_equal 'Hello from downstream', response.body
end
class TestMiddleware < Sinatra::Base
get '/explicit-forward' do
response['X-Middleware'] = 'true'
res = forward
assert_nil res
assert_equal 210, response.status
assert_equal 'true', response['X-Downstream']
assert_equal ['Hello from downstream'], response.body
'Hello after explicit forward'
end
end
it 'forwards the request downstream and integrates the response into the current context' do
response = request.get('/explicit-forward')
assert_equal 210, response.status
assert_equal 'true', response['X-Downstream']
assert_equal 'Hello after explicit forward', response.body
assert_equal '28', response['Content-Length']
end
app_content_length = lambda {|env|
[200, {'Content-Length' => '16'}, 'From downstream!']}
class TestMiddlewareContentLength < Sinatra::Base
get '/forward' do
res = forward
'From after explicit forward!'
end
end
middleware_content_length = TestMiddlewareContentLength.new(app_content_length)
request_content_length = Rack::MockRequest.new(middleware_content_length)
it "sets content length for last response" do
response = request_content_length.get('/forward')
assert_equal '28', response['Content-Length']
end
end
end
sinatra-1.4.3/test/erb_test.rb 0000644 0000041 0000041 00000005073 12161612727 016335 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
class ERBTest < Test::Unit::TestCase
def engine
Tilt::ERBTemplate
end
def setup
Tilt.prefer engine, :erb
super
end
def erb_app(&block)
mock_app do
set :views, File.dirname(__FILE__) + '/views'
get('/', &block)
end
get '/'
end
it 'uses the correct engine' do
assert_equal engine, Tilt[:erb]
end
it 'renders inline ERB strings' do
erb_app { erb '<%= 1 + 1 %>' }
assert ok?
assert_equal '2', body
end
it 'renders .erb files in views path' do
erb_app { erb :hello }
assert ok?
assert_equal "Hello World\n", body
end
it 'takes a :locals option' do
erb_app do
locals = {:foo => 'Bar'}
erb '<%= foo %>', :locals => locals
end
assert ok?
assert_equal 'Bar', body
end
it "renders with inline layouts" do
mock_app do
layout { 'THIS. IS. <%= yield.upcase %>!' }
get('/') { erb 'Sparta' }
end
get '/'
assert ok?
assert_equal 'THIS. IS. SPARTA!', body
end
it "renders with file layouts" do
erb_app { erb 'Hello World', :layout => :layout2 }
assert ok?
assert_body "ERB Layout!\nHello World"
end
it "renders erb with blocks" do
mock_app do
def container
@_out_buf << "THIS."
yield
@_out_buf << "SPARTA!"
end
def is; "IS." end
get('/') { erb '<% container do %> <%= is %> <% end %>' }
end
get '/'
assert ok?
assert_equal 'THIS. IS. SPARTA!', body
end
it "can be used in a nested fashion for partials and whatnot" do
mock_app do
template(:inner) { "<%= 'hi' %>" }
template(:outer) { "<%= erb :inner %>" }
get('/') { erb :outer }
end
get '/'
assert ok?
assert_equal 'hi', body
end
it "can render truly nested layouts by accepting a layout and a block with the contents" do
mock_app do
template(:main_outer_layout) { "Title
\n<%= yield %>" }
template(:an_inner_layout) { "Subtitle
\n<%= yield %>" }
template(:a_page) { "Contents.
\n" }
get('/') do
erb :main_outer_layout, :layout => false do
erb :an_inner_layout do
erb :a_page
end
end
end
end
get '/'
assert ok?
assert_body "Title
\nSubtitle
\nContents.
\n"
end
end
begin
require 'erubis'
class ErubisTest < ERBTest
def engine; Tilt::ErubisTemplate end
end
rescue LoadError
warn "#{$!.to_s}: skipping erubis tests"
end
sinatra-1.4.3/test/helpers_test.rb 0000644 0000041 0000041 00000136343 12161612727 017234 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
require 'date'
require 'json'
class HelpersTest < Test::Unit::TestCase
def test_default
assert true
end
def status_app(code, &block)
code += 2 if [204, 205, 304].include? code
block ||= proc { }
mock_app do
get('/') do
status code
instance_eval(&block).inspect
end
end
get '/'
end
describe 'status' do
it 'sets the response status code' do
status_app 207
assert_equal 207, response.status
end
end
describe 'not_found?' do
it 'is true for status == 404' do
status_app(404) { not_found? }
assert_body 'true'
end
it 'is false for status gt 404' do
status_app(405) { not_found? }
assert_body 'false'
end
it 'is false for status lt 404' do
status_app(403) { not_found? }
assert_body 'false'
end
end
describe 'informational?' do
it 'is true for 1xx status' do
status_app(100 + rand(100)) { informational? }
assert_body 'true'
end
it 'is false for status > 199' do
status_app(200 + rand(400)) { informational? }
assert_body 'false'
end
end
describe 'success?' do
it 'is true for 2xx status' do
status_app(200 + rand(100)) { success? }
assert_body 'true'
end
it 'is false for status < 200' do
status_app(100 + rand(100)) { success? }
assert_body 'false'
end
it 'is false for status > 299' do
status_app(300 + rand(300)) { success? }
assert_body 'false'
end
end
describe 'redirect?' do
it 'is true for 3xx status' do
status_app(300 + rand(100)) { redirect? }
assert_body 'true'
end
it 'is false for status < 300' do
status_app(200 + rand(100)) { redirect? }
assert_body 'false'
end
it 'is false for status > 399' do
status_app(400 + rand(200)) { redirect? }
assert_body 'false'
end
end
describe 'client_error?' do
it 'is true for 4xx status' do
status_app(400 + rand(100)) { client_error? }
assert_body 'true'
end
it 'is false for status < 400' do
status_app(200 + rand(200)) { client_error? }
assert_body 'false'
end
it 'is false for status > 499' do
status_app(500 + rand(100)) { client_error? }
assert_body 'false'
end
end
describe 'server_error?' do
it 'is true for 5xx status' do
status_app(500 + rand(100)) { server_error? }
assert_body 'true'
end
it 'is false for status < 500' do
status_app(200 + rand(300)) { server_error? }
assert_body 'false'
end
end
describe 'body' do
it 'takes a block for deferred body generation' do
mock_app do
get('/') { body { 'Hello World' } }
end
get '/'
assert_equal 'Hello World', body
end
it 'takes a String, Array, or other object responding to #each' do
mock_app { get('/') { body 'Hello World' } }
get '/'
assert_equal 'Hello World', body
end
it 'can be used with other objects' do
mock_app do
get '/' do
body :hello => 'from json'
end
after do
if Hash === response.body
body response.body[:hello]
end
end
end
get '/'
assert_body 'from json'
end
it 'can be set in after filter' do
mock_app do
get('/') { body 'route' }
after { body 'filter' }
end
get '/'
assert_body 'filter'
end
end
describe 'redirect' do
it 'uses a 302 when only a path is given' do
mock_app do
get('/') do
redirect '/foo'
fail 'redirect should halt'
end
end
get '/'
assert_equal 302, status
assert_equal '', body
assert_equal 'http://example.org/foo', response['Location']
end
it 'uses the code given when specified' do
mock_app do
get('/') do
redirect '/foo', 301
fail 'redirect should halt'
end
end
get '/'
assert_equal 301, status
assert_equal '', body
assert_equal 'http://example.org/foo', response['Location']
end
it 'redirects back to request.referer when passed back' do
mock_app { get('/try_redirect') { redirect back } }
request = Rack::MockRequest.new(@app)
response = request.get('/try_redirect', 'HTTP_REFERER' => '/foo')
assert_equal 302, response.status
assert_equal 'http://example.org/foo', response['Location']
end
it 'redirects using a non-standard HTTP port' do
mock_app { get('/') { redirect '/foo' } }
request = Rack::MockRequest.new(@app)
response = request.get('/', 'SERVER_PORT' => '81')
assert_equal 'http://example.org:81/foo', response['Location']
end
it 'redirects using a non-standard HTTPS port' do
mock_app { get('/') { redirect '/foo' } }
request = Rack::MockRequest.new(@app)
response = request.get('/', 'SERVER_PORT' => '444')
assert_equal 'http://example.org:444/foo', response['Location']
end
it 'uses 303 for post requests if request is HTTP 1.1' do
mock_app { post('/') { redirect '/'} }
post('/', {}, 'HTTP_VERSION' => 'HTTP/1.1')
assert_equal 303, status
assert_equal '', body
assert_equal 'http://example.org/', response['Location']
end
it 'uses 302 for post requests if request is HTTP 1.0' do
mock_app { post('/') { redirect '/'} }
post('/', {}, 'HTTP_VERSION' => 'HTTP/1.0')
assert_equal 302, status
assert_equal '', body
assert_equal 'http://example.org/', response['Location']
end
it 'works behind a reverse proxy' do
mock_app { get('/') { redirect '/foo' } }
request = Rack::MockRequest.new(@app)
response = request.get('/', 'HTTP_X_FORWARDED_HOST' => 'example.com', 'SERVER_PORT' => '8080')
assert_equal 'http://example.com/foo', response['Location']
end
it 'accepts absolute URIs' do
mock_app do
get('/') do
redirect 'http://google.com'
fail 'redirect should halt'
end
end
get '/'
assert_equal 302, status
assert_equal '', body
assert_equal 'http://google.com', response['Location']
end
it 'accepts absolute URIs with a different schema' do
mock_app do
get('/') do
redirect 'mailto:jsmith@example.com'
fail 'redirect should halt'
end
end
get '/'
assert_equal 302, status
assert_equal '', body
assert_equal 'mailto:jsmith@example.com', response['Location']
end
it 'accepts a URI object instead of a String' do
mock_app do
get('/') { redirect URI.parse('http://sinatrarb.com') }
end
get '/'
assert_equal 302, status
assert_equal '', body
assert_equal 'http://sinatrarb.com', response['Location']
end
end
describe 'error' do
it 'sets a status code and halts' do
mock_app do
get('/') do
error 501
fail 'error should halt'
end
end
get '/'
assert_equal 501, status
assert_equal '', body
end
it 'takes an optional body' do
mock_app do
get('/') do
error 501, 'FAIL'
fail 'error should halt'
end
end
get '/'
assert_equal 501, status
assert_equal 'FAIL', body
end
it 'should not invoke error handler when setting status inside an error handler' do
mock_app do
disable :raise_errors
not_found do
body "not_found handler"
status 404
end
error do
body "error handler"
status 404
end
get '/' do
raise
end
end
get '/'
assert_equal 404, status
assert_equal 'error handler', body
end
it 'should not reset the content-type to html for error handlers' do
mock_app do
disable :raise_errors
before { content_type "application/json;charset=utf-8" }
not_found { JSON.dump("error" => "Not Found") }
end
get '/'
assert_equal 404, status
assert_equal 'application/json;charset=utf-8', response.content_type
end
it 'should not invoke error handler when halting with 500 inside an error handler' do
mock_app do
disable :raise_errors
not_found do
body "not_found handler"
halt 404
end
error do
body "error handler"
halt 404
end
get '/' do
raise
end
end
get '/'
assert_equal 404, status
assert_equal 'error handler', body
end
it 'should not invoke not_found handler when halting with 404 inside a not found handler' do
mock_app do
disable :raise_errors
not_found do
body "not_found handler"
halt 500
end
error do
body "error handler"
halt 500
end
end
get '/'
assert_equal 500, status
assert_equal 'not_found handler', body
end
it 'uses a 500 status code when first argument is a body' do
mock_app do
get('/') do
error 'FAIL'
fail 'error should halt'
end
end
get '/'
assert_equal 500, status
assert_equal 'FAIL', body
end
end
describe 'not_found' do
it 'halts with a 404 status' do
mock_app do
get('/') do
not_found
fail 'not_found should halt'
end
end
get '/'
assert_equal 404, status
assert_equal '', body
end
it 'does not set a X-Cascade header' do
mock_app do
get('/') do
not_found
fail 'not_found should halt'
end
end
get '/'
assert_equal 404, status
assert_equal nil, response.headers['X-Cascade']
end
end
describe 'headers' do
it 'sets headers on the response object when given a Hash' do
mock_app do
get('/') do
headers 'X-Foo' => 'bar', 'X-Baz' => 'bling'
'kthx'
end
end
get '/'
assert ok?
assert_equal 'bar', response['X-Foo']
assert_equal 'bling', response['X-Baz']
assert_equal 'kthx', body
end
it 'returns the response headers hash when no hash provided' do
mock_app do
get('/') do
headers['X-Foo'] = 'bar'
'kthx'
end
end
get '/'
assert ok?
assert_equal 'bar', response['X-Foo']
end
end
describe 'session' do
it 'uses the existing rack.session' do
mock_app do
get('/') do
session[:foo]
end
end
get('/', {}, { 'rack.session' => { :foo => 'bar' } })
assert_equal 'bar', body
end
it 'creates a new session when none provided' do
mock_app do
enable :sessions
get('/') do
assert session[:foo].nil?
session[:foo] = 'bar'
redirect '/hi'
end
get('/hi') do
"hi #{session[:foo]}"
end
end
get '/'
follow_redirect!
assert_equal 'hi bar', body
end
it 'inserts session middleware' do
mock_app do
enable :sessions
get('/') do
assert env['rack.session']
assert env['rack.session.options']
'ok'
end
end
get '/'
assert_body 'ok'
end
it 'sets a default session secret' do
mock_app do
enable :sessions
get('/') do
secret = env['rack.session.options'][:secret]
assert secret
assert_equal secret, settings.session_secret
'ok'
end
end
get '/'
assert_body 'ok'
end
it 'allows disabling session secret' do
mock_app do
enable :sessions
disable :session_secret
get('/') do
assert !env['rack.session.options'].include?(:session_secret)
'ok'
end
end
# Silence warnings since Rack::Session::Cookie complains about the non-present session secret
silence_warnings do
get '/'
end
assert_body 'ok'
end
it 'accepts an options hash' do
mock_app do
set :sessions, :foo => :bar
get('/') do
assert_equal env['rack.session.options'][:foo], :bar
'ok'
end
end
get '/'
assert_body 'ok'
end
end
describe 'mime_type' do
include Sinatra::Helpers
it "looks up mime types in Rack's MIME registry" do
Rack::Mime::MIME_TYPES['.foo'] = 'application/foo'
assert_equal 'application/foo', mime_type('foo')
assert_equal 'application/foo', mime_type('.foo')
assert_equal 'application/foo', mime_type(:foo)
end
it 'returns nil when given nil' do
assert mime_type(nil).nil?
end
it 'returns nil when media type not registered' do
assert mime_type(:bizzle).nil?
end
it 'returns the argument when given a media type string' do
assert_equal 'text/plain', mime_type('text/plain')
end
it 'turns AcceptEntry into String' do
type = mime_type(Sinatra::Request::AcceptEntry.new('text/plain'))
assert_equal String, type.class
assert_equal 'text/plain', type
end
end
test 'Base.mime_type registers mime type' do
mock_app do
mime_type :foo, 'application/foo'
get('/') do
"foo is #{mime_type(:foo)}"
end
end
get '/'
assert_equal 'foo is application/foo', body
end
describe 'content_type' do
it 'sets the Content-Type header' do
mock_app do
get('/') do
content_type 'text/plain'
'Hello World'
end
end
get '/'
assert_equal 'text/plain;charset=utf-8', response['Content-Type']
assert_equal 'Hello World', body
end
it 'takes media type parameters (like charset=)' do
mock_app do
get('/') do
content_type 'text/html', :charset => 'latin1'
"Hello, World
"
end
end
get '/'
assert ok?
assert_equal 'text/html;charset=latin1', response['Content-Type']
assert_equal "Hello, World
", body
end
it "looks up symbols in Rack's mime types dictionary" do
Rack::Mime::MIME_TYPES['.foo'] = 'application/foo'
mock_app do
get('/foo.xml') do
content_type :foo
"I AM FOO"
end
end
get '/foo.xml'
assert ok?
assert_equal 'application/foo', response['Content-Type']
assert_equal 'I AM FOO', body
end
it 'fails when no mime type is registered for the argument provided' do
mock_app do
get('/foo.xml') do
content_type :bizzle
"I AM FOO"
end
end
assert_raise(RuntimeError) { get '/foo.xml' }
end
it 'only sets default charset for specific mime types' do
tests_ran = false
mock_app do
mime_type :foo, 'text/foo'
mime_type :bar, 'application/bar'
mime_type :baz, 'application/baz'
add_charset << mime_type(:baz)
get('/') do
assert_equal content_type(:txt), 'text/plain;charset=utf-8'
assert_equal content_type(:css), 'text/css;charset=utf-8'
assert_equal content_type(:html), 'text/html;charset=utf-8'
assert_equal content_type(:foo), 'text/foo;charset=utf-8'
assert_equal content_type(:xml), 'application/xml;charset=utf-8'
assert_equal content_type(:xhtml), 'application/xhtml+xml;charset=utf-8'
assert_equal content_type(:js), 'application/javascript;charset=utf-8'
assert_equal content_type(:json), 'application/json;charset=utf-8'
assert_equal content_type(:bar), 'application/bar'
assert_equal content_type(:png), 'image/png'
assert_equal content_type(:baz), 'application/baz;charset=utf-8'
tests_ran = true
"done"
end
end
get '/'
assert tests_ran
end
it 'handles already present params' do
mock_app do
get('/') do
content_type 'foo/bar;level=1', :charset => 'utf-8'
'ok'
end
end
get '/'
assert_equal 'foo/bar;level=1, charset=utf-8', response['Content-Type']
end
it 'does not add charset if present' do
mock_app do
get('/') do
content_type 'text/plain;charset=utf-16'
'ok'
end
end
get '/'
assert_equal 'text/plain;charset=utf-16', response['Content-Type']
end
it 'properly encodes parameters with delimiter characters' do
mock_app do
before '/comma' do
content_type 'image/png', :comment => 'Hello, world!'
end
before '/semicolon' do
content_type 'image/png', :comment => 'semi;colon'
end
before '/quote' do
content_type 'image/png', :comment => '"Whatever."'
end
get('*') { 'ok' }
end
get '/comma'
assert_equal 'image/png;comment="Hello, world!"', response['Content-Type']
get '/semicolon'
assert_equal 'image/png;comment="semi;colon"', response['Content-Type']
get '/quote'
assert_equal 'image/png;comment="\"Whatever.\""', response['Content-Type']
end
end
describe 'attachment' do
def attachment_app(filename=nil)
mock_app do
get('/attachment') do
attachment filename
response.write("")
end
end
end
it 'sets the Content-Type response header' do
attachment_app('test.xml')
get '/attachment'
assert_equal 'application/xml;charset=utf-8', response['Content-Type']
assert_equal '', body
end
it 'sets the Content-Type response header without extname' do
attachment_app('test')
get '/attachment'
assert_equal 'text/html;charset=utf-8', response['Content-Type']
assert_equal '', body
end
it 'sets the Content-Type response header with extname' do
mock_app do
get('/attachment') do
content_type :atom
attachment 'test.xml'
response.write("")
end
end
get '/attachment'
assert_equal 'application/atom+xml', response['Content-Type']
assert_equal '', body
end
end
describe 'send_file' do
setup do
@file = File.dirname(__FILE__) + '/file.txt'
File.open(@file, 'wb') { |io| io.write('Hello World') }
end
def teardown
File.unlink @file
@file = nil
end
def send_file_app(opts={})
path = @file
mock_app {
get '/file.txt' do
send_file path, opts
end
}
end
it "sends the contents of the file" do
send_file_app
get '/file.txt'
assert ok?
assert_equal 'Hello World', body
end
it 'sets the Content-Type response header if a mime-type can be located' do
send_file_app
get '/file.txt'
assert_equal 'text/plain;charset=utf-8', response['Content-Type']
end
it 'sets the Content-Type response header if type option is set to a file extension' do
send_file_app :type => 'html'
get '/file.txt'
assert_equal 'text/html;charset=utf-8', response['Content-Type']
end
it 'sets the Content-Type response header if type option is set to a mime type' do
send_file_app :type => 'application/octet-stream'
get '/file.txt'
assert_equal 'application/octet-stream', response['Content-Type']
end
it 'sets the Content-Length response header' do
send_file_app
get '/file.txt'
assert_equal 'Hello World'.length.to_s, response['Content-Length']
end
it 'sets the Last-Modified response header' do
send_file_app
get '/file.txt'
assert_equal File.mtime(@file).httpdate, response['Last-Modified']
end
it 'allows passing in a different Last-Modified response header with :last_modified' do
time = Time.now
send_file_app :last_modified => time
get '/file.txt'
assert_equal time.httpdate, response['Last-Modified']
end
it "returns a 404 when not found" do
mock_app {
get('/') { send_file 'this-file-does-not-exist.txt' }
}
get '/'
assert not_found?
end
it "does not set the Content-Disposition header by default" do
send_file_app
get '/file.txt'
assert_nil response['Content-Disposition']
end
it "sets the Content-Disposition header when :disposition set to 'attachment'" do
send_file_app :disposition => 'attachment'
get '/file.txt'
assert_equal 'attachment; filename="file.txt"', response['Content-Disposition']
end
it "does not set add a file name if filename is false" do
send_file_app :disposition => 'inline', :filename => false
get '/file.txt'
assert_equal 'inline', response['Content-Disposition']
end
it "sets the Content-Disposition header when :disposition set to 'inline'" do
send_file_app :disposition => 'inline'
get '/file.txt'
assert_equal 'inline; filename="file.txt"', response['Content-Disposition']
end
it "sets the Content-Disposition header when :filename provided" do
send_file_app :filename => 'foo.txt'
get '/file.txt'
assert_equal 'attachment; filename="foo.txt"', response['Content-Disposition']
end
it 'allows setting a custom status code' do
send_file_app :status => 201
get '/file.txt'
assert_status 201
end
it "is able to send files with unknown mime type" do
@file = File.dirname(__FILE__) + '/file.foobar'
File.open(@file, 'wb') { |io| io.write('Hello World') }
send_file_app
get '/file.txt'
assert_equal 'application/octet-stream', response['Content-Type']
end
it "does not override Content-Type if already set and no explicit type is given" do
path = @file
mock_app do
get('/') do
content_type :png
send_file path
end
end
get '/'
assert_equal 'image/png', response['Content-Type']
end
it "does override Content-Type even if already set, if explicit type is given" do
path = @file
mock_app do
get('/') do
content_type :png
send_file path, :type => :gif
end
end
get '/'
assert_equal 'image/gif', response['Content-Type']
end
end
describe 'cache_control' do
setup do
mock_app do
get('/foo') do
cache_control :public, :no_cache, :max_age => 60.0
'Hello World'
end
get('/bar') do
cache_control :public, :no_cache
'Hello World'
end
end
end
it 'sets the Cache-Control header' do
get '/foo'
assert_equal ['public', 'no-cache', 'max-age=60'], response['Cache-Control'].split(', ')
end
it 'last argument does not have to be a hash' do
get '/bar'
assert_equal ['public', 'no-cache'], response['Cache-Control'].split(', ')
end
end
describe 'expires' do
setup do
mock_app do
get('/foo') do
expires 60, :public, :no_cache
'Hello World'
end
get('/bar') { expires Time.now }
get('/baz') { expires Time.at(0) }
get('/blah') do
obj = Object.new
def obj.method_missing(*a, &b) 60.send(*a, &b) end
def obj.is_a?(thing) 60.is_a?(thing) end
expires obj, :public, :no_cache
'Hello World'
end
get('/boom') { expires '9999' }
end
end
it 'sets the Cache-Control header' do
get '/foo'
assert_equal ['public', 'no-cache', 'max-age=60'], response['Cache-Control'].split(', ')
end
it 'sets the Expires header' do
get '/foo'
assert_not_nil response['Expires']
end
it 'allows passing Time.now objects' do
get '/bar'
assert_not_nil response['Expires']
end
it 'allows passing Time.at objects' do
get '/baz'
assert_equal 'Thu, 01 Jan 1970 00:00:00 GMT', response['Expires']
end
it 'accepts values pretending to be a Numeric (like ActiveSupport::Duration)' do
get '/blah'
assert_equal ['public', 'no-cache', 'max-age=60'], response['Cache-Control'].split(', ')
end
it 'fails when Time.parse raises an ArgumentError' do
assert_raise(ArgumentError) { get '/boom' }
end
end
describe 'last_modified' do
it 'ignores nil' do
mock_app { get('/') { last_modified nil; 200; } }
get '/'
assert ! response['Last-Modified']
end
it 'does not change a status other than 200' do
mock_app do
get('/') do
status 299
last_modified Time.at(0)
'ok'
end
end
get('/', {}, 'HTTP_IF_MODIFIED_SINCE' => 'Sun, 26 Sep 2030 23:43:52 GMT')
assert_status 299
assert_body 'ok'
end
[Time.now, DateTime.now, Date.today, Time.now.to_i,
Struct.new(:to_time).new(Time.now) ].each do |last_modified_time|
describe "with #{last_modified_time.class.name}" do
setup do
mock_app do
get('/') do
last_modified last_modified_time
'Boo!'
end
end
wrapper = Object.new.extend Sinatra::Helpers
@last_modified_time = wrapper.time_for last_modified_time
end
# fixes strange missing test error when running complete test suite.
it("does not complain about missing tests") { }
context "when there's no If-Modified-Since header" do
it 'sets the Last-Modified header to a valid RFC 2616 date value' do
get '/'
assert_equal @last_modified_time.httpdate, response['Last-Modified']
end
it 'conditional GET misses and returns a body' do
get '/'
assert_equal 200, status
assert_equal 'Boo!', body
end
end
context "when there's an invalid If-Modified-Since header" do
it 'sets the Last-Modified header to a valid RFC 2616 date value' do
get('/', {}, { 'HTTP_IF_MODIFIED_SINCE' => 'a really weird date' })
assert_equal @last_modified_time.httpdate, response['Last-Modified']
end
it 'conditional GET misses and returns a body' do
get('/', {}, { 'HTTP_IF_MODIFIED_SINCE' => 'a really weird date' })
assert_equal 200, status
assert_equal 'Boo!', body
end
end
context "when the resource has been modified since the If-Modified-Since header date" do
it 'sets the Last-Modified header to a valid RFC 2616 date value' do
get('/', {}, { 'HTTP_IF_MODIFIED_SINCE' => (@last_modified_time - 1).httpdate })
assert_equal @last_modified_time.httpdate, response['Last-Modified']
end
it 'conditional GET misses and returns a body' do
get('/', {}, { 'HTTP_IF_MODIFIED_SINCE' => (@last_modified_time - 1).httpdate })
assert_equal 200, status
assert_equal 'Boo!', body
end
it 'does not rely on string comparison' do
mock_app do
get('/compare') do
last_modified "Mon, 18 Oct 2010 20:57:11 GMT"
"foo"
end
end
get('/compare', {}, { 'HTTP_IF_MODIFIED_SINCE' => 'Sun, 26 Sep 2010 23:43:52 GMT' })
assert_equal 200, status
assert_equal 'foo', body
get('/compare', {}, { 'HTTP_IF_MODIFIED_SINCE' => 'Sun, 26 Sep 2030 23:43:52 GMT' })
assert_equal 304, status
assert_equal '', body
end
end
context "when the resource has been modified on the exact If-Modified-Since header date" do
it 'sets the Last-Modified header to a valid RFC 2616 date value' do
get('/', {}, { 'HTTP_IF_MODIFIED_SINCE' => @last_modified_time.httpdate })
assert_equal @last_modified_time.httpdate, response['Last-Modified']
end
it 'conditional GET matches and halts' do
get( '/', {}, { 'HTTP_IF_MODIFIED_SINCE' => @last_modified_time.httpdate })
assert_equal 304, status
assert_equal '', body
end
end
context "when the resource hasn't been modified since the If-Modified-Since header date" do
it 'sets the Last-Modified header to a valid RFC 2616 date value' do
get('/', {}, { 'HTTP_IF_MODIFIED_SINCE' => (@last_modified_time + 1).httpdate })
assert_equal @last_modified_time.httpdate, response['Last-Modified']
end
it 'conditional GET matches and halts' do
get('/', {}, { 'HTTP_IF_MODIFIED_SINCE' => (@last_modified_time + 1).httpdate })
assert_equal 304, status
assert_equal '', body
end
end
context "If-Unmodified-Since" do
it 'results in 200 if resource has not been modified' do
get('/', {}, { 'HTTP_IF_UNMODIFIED_SINCE' => 'Sun, 26 Sep 2030 23:43:52 GMT' })
assert_equal 200, status
assert_equal 'Boo!', body
end
it 'results in 412 if resource has been modified' do
get('/', {}, { 'HTTP_IF_UNMODIFIED_SINCE' => Time.at(0).httpdate })
assert_equal 412, status
assert_equal '', body
end
end
end
end
end
describe 'etag' do
context "safe requests" do
it 'returns 200 for normal requests' do
mock_app do
get('/') do
etag 'foo'
'ok'
end
end
get '/'
assert_status 200
assert_body 'ok'
end
context "If-None-Match" do
it 'returns 304 when If-None-Match is *' do
mock_app do
get('/') do
etag 'foo'
'ok'
end
end
get('/', {}, 'HTTP_IF_NONE_MATCH' => '*')
assert_status 304
assert_body ''
end
it 'returns 200 when If-None-Match is * for new resources' do
mock_app do
get('/') do
etag 'foo', :new_resource => true
'ok'
end
end
get('/', {}, 'HTTP_IF_NONE_MATCH' => '*')
assert_status 200
assert_body 'ok'
end
it 'returns 304 when If-None-Match is * for existing resources' do
mock_app do
get('/') do
etag 'foo', :new_resource => false
'ok'
end
end
get('/', {}, 'HTTP_IF_NONE_MATCH' => '*')
assert_status 304
assert_body ''
end
it 'returns 304 when If-None-Match is the etag' do
mock_app do
get('/') do
etag 'foo'
'ok'
end
end
get('/', {}, 'HTTP_IF_NONE_MATCH' => '"foo"')
assert_status 304
assert_body ''
end
it 'returns 304 when If-None-Match includes the etag' do
mock_app do
get('/') do
etag 'foo'
'ok'
end
end
get('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar", "foo"')
assert_status 304
assert_body ''
end
it 'returns 200 when If-None-Match does not include the etag' do
mock_app do
get('/') do
etag 'foo'
'ok'
end
end
get('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar"')
assert_status 200
assert_body 'ok'
end
it 'ignores If-Modified-Since if If-None-Match does not match' do
mock_app do
get('/') do
etag 'foo'
last_modified Time.at(0)
'ok'
end
end
get('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar"')
assert_status 200
assert_body 'ok'
end
it 'does not change a status code other than 2xx or 304' do
mock_app do
get('/') do
status 499
etag 'foo'
'ok'
end
end
get('/', {}, 'HTTP_IF_NONE_MATCH' => '"foo"')
assert_status 499
assert_body 'ok'
end
it 'does change 2xx status codes' do
mock_app do
get('/') do
status 299
etag 'foo'
'ok'
end
end
get('/', {}, 'HTTP_IF_NONE_MATCH' => '"foo"')
assert_status 304
assert_body ''
end
it 'does not send a body on 304 status codes' do
mock_app do
get('/') do
status 304
etag 'foo'
'ok'
end
end
get('/', {}, 'HTTP_IF_NONE_MATCH' => '"foo"')
assert_status 304
assert_body ''
end
end
context "If-Match" do
it 'returns 200 when If-Match is the etag' do
mock_app do
get('/') do
etag 'foo'
'ok'
end
end
get('/', {}, 'HTTP_IF_MATCH' => '"foo"')
assert_status 200
assert_body 'ok'
end
it 'returns 200 when If-Match includes the etag' do
mock_app do
get('/') do
etag 'foo'
'ok'
end
end
get('/', {}, 'HTTP_IF_MATCH' => '"foo", "bar"')
assert_status 200
assert_body 'ok'
end
it 'returns 200 when If-Match is *' do
mock_app do
get('/') do
etag 'foo'
'ok'
end
end
get('/', {}, 'HTTP_IF_MATCH' => '*')
assert_status 200
assert_body 'ok'
end
it 'returns 412 when If-Match is * for new resources' do
mock_app do
get('/') do
etag 'foo', :new_resource => true
'ok'
end
end
get('/', {}, 'HTTP_IF_MATCH' => '*')
assert_status 412
assert_body ''
end
it 'returns 200 when If-Match is * for existing resources' do
mock_app do
get('/') do
etag 'foo', :new_resource => false
'ok'
end
end
get('/', {}, 'HTTP_IF_MATCH' => '*')
assert_status 200
assert_body 'ok'
end
it 'returns 412 when If-Match does not include the etag' do
mock_app do
get('/') do
etag 'foo'
'ok'
end
end
get('/', {}, 'HTTP_IF_MATCH' => '"bar"')
assert_status 412
assert_body ''
end
end
end
context "idempotent requests" do
it 'returns 200 for normal requests' do
mock_app do
put('/') do
etag 'foo'
'ok'
end
end
put '/'
assert_status 200
assert_body 'ok'
end
context "If-None-Match" do
it 'returns 412 when If-None-Match is *' do
mock_app do
put('/') do
etag 'foo'
'ok'
end
end
put('/', {}, 'HTTP_IF_NONE_MATCH' => '*')
assert_status 412
assert_body ''
end
it 'returns 200 when If-None-Match is * for new resources' do
mock_app do
put('/') do
etag 'foo', :new_resource => true
'ok'
end
end
put('/', {}, 'HTTP_IF_NONE_MATCH' => '*')
assert_status 200
assert_body 'ok'
end
it 'returns 412 when If-None-Match is * for existing resources' do
mock_app do
put('/') do
etag 'foo', :new_resource => false
'ok'
end
end
put('/', {}, 'HTTP_IF_NONE_MATCH' => '*')
assert_status 412
assert_body ''
end
it 'returns 412 when If-None-Match is the etag' do
mock_app do
put '/' do
etag 'foo'
'ok'
end
end
put('/', {}, 'HTTP_IF_NONE_MATCH' => '"foo"')
assert_status 412
assert_body ''
end
it 'returns 412 when If-None-Match includes the etag' do
mock_app do
put('/') do
etag 'foo'
'ok'
end
end
put('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar", "foo"')
assert_status 412
assert_body ''
end
it 'returns 200 when If-None-Match does not include the etag' do
mock_app do
put('/') do
etag 'foo'
'ok'
end
end
put('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar"')
assert_status 200
assert_body 'ok'
end
it 'ignores If-Modified-Since if If-None-Match does not match' do
mock_app do
put('/') do
etag 'foo'
last_modified Time.at(0)
'ok'
end
end
put('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar"')
assert_status 200
assert_body 'ok'
end
end
context "If-Match" do
it 'returns 200 when If-Match is the etag' do
mock_app do
put('/') do
etag 'foo'
'ok'
end
end
put('/', {}, 'HTTP_IF_MATCH' => '"foo"')
assert_status 200
assert_body 'ok'
end
it 'returns 200 when If-Match includes the etag' do
mock_app do
put('/') do
etag 'foo'
'ok'
end
end
put('/', {}, 'HTTP_IF_MATCH' => '"foo", "bar"')
assert_status 200
assert_body 'ok'
end
it 'returns 200 when If-Match is *' do
mock_app do
put('/') do
etag 'foo'
'ok'
end
end
put('/', {}, 'HTTP_IF_MATCH' => '*')
assert_status 200
assert_body 'ok'
end
it 'returns 412 when If-Match is * for new resources' do
mock_app do
put('/') do
etag 'foo', :new_resource => true
'ok'
end
end
put('/', {}, 'HTTP_IF_MATCH' => '*')
assert_status 412
assert_body ''
end
it 'returns 200 when If-Match is * for existing resources' do
mock_app do
put('/') do
etag 'foo', :new_resource => false
'ok'
end
end
put('/', {}, 'HTTP_IF_MATCH' => '*')
assert_status 200
assert_body 'ok'
end
it 'returns 412 when If-Match does not include the etag' do
mock_app do
put('/') do
etag 'foo'
'ok'
end
end
put('/', {}, 'HTTP_IF_MATCH' => '"bar"')
assert_status 412
assert_body ''
end
end
end
context "post requests" do
it 'returns 200 for normal requests' do
mock_app do
post('/') do
etag 'foo'
'ok'
end
end
post('/')
assert_status 200
assert_body 'ok'
end
context "If-None-Match" do
it 'returns 200 when If-None-Match is *' do
mock_app do
post('/') do
etag 'foo'
'ok'
end
end
post('/', {}, 'HTTP_IF_NONE_MATCH' => '*')
assert_status 200
assert_body 'ok'
end
it 'returns 200 when If-None-Match is * for new resources' do
mock_app do
post('/') do
etag 'foo', :new_resource => true
'ok'
end
end
post('/', {}, 'HTTP_IF_NONE_MATCH' => '*')
assert_status 200
assert_body 'ok'
end
it 'returns 412 when If-None-Match is * for existing resources' do
mock_app do
post('/') do
etag 'foo', :new_resource => false
'ok'
end
end
post('/', {}, 'HTTP_IF_NONE_MATCH' => '*')
assert_status 412
assert_body ''
end
it 'returns 412 when If-None-Match is the etag' do
mock_app do
post('/') do
etag 'foo'
'ok'
end
end
post('/', {}, 'HTTP_IF_NONE_MATCH' => '"foo"')
assert_status 412
assert_body ''
end
it 'returns 412 when If-None-Match includes the etag' do
mock_app do
post('/') do
etag 'foo'
'ok'
end
end
post('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar", "foo"')
assert_status 412
assert_body ''
end
it 'returns 200 when If-None-Match does not include the etag' do
mock_app do
post('/') do
etag 'foo'
'ok'
end
end
post('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar"')
assert_status 200
assert_body 'ok'
end
it 'ignores If-Modified-Since if If-None-Match does not match' do
mock_app do
post('/') do
etag 'foo'
last_modified Time.at(0)
'ok'
end
end
post('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar"')
assert_status 200
assert_body 'ok'
end
end
context "If-Match" do
it 'returns 200 when If-Match is the etag' do
mock_app do
post('/') do
etag 'foo'
'ok'
end
end
post('/', {}, 'HTTP_IF_MATCH' => '"foo"')
assert_status 200
assert_body 'ok'
end
it 'returns 200 when If-Match includes the etag' do
mock_app do
post('/') do
etag 'foo'
'ok'
end
end
post('/', {}, 'HTTP_IF_MATCH' => '"foo", "bar"')
assert_status 200
assert_body 'ok'
end
it 'returns 412 when If-Match is *' do
mock_app do
post('/') do
etag 'foo'
'ok'
end
end
post('/', {}, 'HTTP_IF_MATCH' => '*')
assert_status 412
assert_body ''
end
it 'returns 412 when If-Match is * for new resources' do
mock_app do
post('/') do
etag 'foo', :new_resource => true
'ok'
end
end
post('/', {}, 'HTTP_IF_MATCH' => '*')
assert_status 412
assert_body ''
end
it 'returns 200 when If-Match is * for existing resources' do
mock_app do
post('/') do
etag 'foo', :new_resource => false
'ok'
end
end
post('/', {}, 'HTTP_IF_MATCH' => '*')
assert_status 200
assert_body 'ok'
end
it 'returns 412 when If-Match does not include the etag' do
mock_app do
post('/') do
etag 'foo'
'ok'
end
end
post('/', {}, 'HTTP_IF_MATCH' => '"bar"')
assert_status 412
assert_body ''
end
end
end
it 'uses a weak etag with the :weak option' do
mock_app do
get('/') do
etag 'FOO', :weak
"that's weak, dude."
end
end
get '/'
assert_equal 'W/"FOO"', response['ETag']
end
it 'raises an ArgumentError for an invalid strength' do
mock_app do
get('/') do
etag 'FOO', :w00t
"that's weak, dude."
end
end
assert_raise(ArgumentError) { get('/') }
end
end
describe 'back' do
it "makes redirecting back pretty" do
mock_app { get('/foo') { redirect back } }
get('/foo', {}, 'HTTP_REFERER' => 'http://github.com')
assert redirect?
assert_equal "http://github.com", response.location
end
end
describe 'uri' do
it 'generates absolute urls' do
mock_app { get('/') { uri }}
get '/'
assert_equal 'http://example.org/', body
end
it 'includes path_info' do
mock_app { get('/:name') { uri }}
get '/foo'
assert_equal 'http://example.org/foo', body
end
it 'allows passing an alternative to path_info' do
mock_app { get('/:name') { uri '/bar' }}
get '/foo'
assert_equal 'http://example.org/bar', body
end
it 'includes script_name' do
mock_app { get('/:name') { uri '/bar' }}
get '/foo', {}, { "SCRIPT_NAME" => '/foo' }
assert_equal 'http://example.org/foo/bar', body
end
it 'handles absolute URIs' do
mock_app { get('/') { uri 'http://google.com' }}
get '/'
assert_equal 'http://google.com', body
end
it 'handles different protocols' do
mock_app { get('/') { uri 'mailto:jsmith@example.com' }}
get '/'
assert_equal 'mailto:jsmith@example.com', body
end
it 'is aliased to #url' do
mock_app { get('/') { url }}
get '/'
assert_equal 'http://example.org/', body
end
it 'is aliased to #to' do
mock_app { get('/') { to }}
get '/'
assert_equal 'http://example.org/', body
end
end
describe 'logger' do
it 'logging works when logging is enabled' do
mock_app do
enable :logging
get('/') do
logger.info "Program started"
logger.warn "Nothing to do!"
end
end
io = StringIO.new
get '/', {}, 'rack.errors' => io
assert io.string.include?("INFO -- : Program started")
assert io.string.include?("WARN -- : Nothing to do")
end
it 'logging works when logging is disable, but no output is produced' do
mock_app do
disable :logging
get('/') do
logger.info "Program started"
logger.warn "Nothing to do!"
end
end
io = StringIO.new
get '/', {}, 'rack.errors' => io
assert !io.string.include?("INFO -- : Program started")
assert !io.string.include?("WARN -- : Nothing to do")
end
it 'does not create a logger when logging is set to nil' do
mock_app do
set :logging, nil
get('/') { logger.inspect }
end
get '/'
assert_body 'nil'
end
end
module ::HelperOne; def one; '1'; end; end
module ::HelperTwo; def two; '2'; end; end
describe 'Adding new helpers' do
it 'takes a list of modules to mix into the app' do
mock_app do
helpers ::HelperOne, ::HelperTwo
get('/one') { one }
get('/two') { two }
end
get '/one'
assert_equal '1', body
get '/two'
assert_equal '2', body
end
it 'takes a block to mix into the app' do
mock_app do
helpers do
def foo
'foo'
end
end
get('/') { foo }
end
get '/'
assert_equal 'foo', body
end
it 'evaluates the block in class context so that methods can be aliased' do
mock_app do
helpers { alias_method :h, :escape_html }
get('/') { h('42 < 43') }
end
get '/'
assert ok?
assert_equal '42 < 43', body
end
end
end
sinatra-1.4.3/test/creole_test.rb 0000644 0000041 0000041 00000002745 12161612727 017041 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
begin
require 'creole'
class CreoleTest < Test::Unit::TestCase
def creole_app(&block)
mock_app do
set :views, File.dirname(__FILE__) + '/views'
get('/', &block)
end
get '/'
end
it 'renders inline creole strings' do
creole_app { creole '= Hiya' }
assert ok?
assert_body "Hiya
"
end
it 'renders .creole files in views path' do
creole_app { creole :hello }
assert ok?
assert_body "Hello From Creole
"
end
it "raises error if template not found" do
mock_app { get('/') { creole :no_such_template } }
assert_raise(Errno::ENOENT) { get('/') }
end
it "renders with inline layouts" do
mock_app do
layout { 'THIS. IS. #{yield.upcase}!' }
get('/') { creole 'Sparta', :layout_engine => :str }
end
get '/'
assert ok?
assert_like 'THIS. IS. SPARTA
!', body
end
it "renders with file layouts" do
creole_app do
creole 'Hello World', :layout => :layout2, :layout_engine => :erb
end
assert ok?
assert_body "ERB Layout!\nHello World
"
end
it "can be used in a nested fashion for partials and whatnot" do
mock_app do
template(:inner) { "hi" }
template(:outer) { "<%= creole :inner %>" }
get('/') { erb :outer }
end
get '/'
assert ok?
assert_like 'hi
', body
end
end
rescue LoadError
warn "#{$!.to_s}: skipping creole tests"
end
sinatra-1.4.3/test/integration_test.rb 0000644 0000041 0000041 00000005050 12161612727 020103 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
require File.expand_path('../integration_helper', __FILE__)
# These tests start a real server and talk to it over TCP.
# Every test runs with every detected server.
#
# See test/integration/app.rb for the code of the app we test against.
class IntegrationTest < Test::Unit::TestCase
extend IntegrationHelper
attr_accessor :server
it('sets the app_file') { assert_equal server.app_file, server.get("/app_file") }
it('only extends main') { assert_equal "true", server.get("/mainonly") }
it 'logs once in development mode' do
next if server.puma? or RUBY_ENGINE == 'jruby'
random = "%064x" % Kernel.rand(2**256-1)
server.get "/ping?x=#{random}"
count = server.log.scan("GET /ping?x=#{random}").count
if server.net_http_server?
assert_equal 0, count
elsif server.webrick?
assert(count > 0)
else
assert_equal(1, count)
end
end
it 'streams' do
next if server.webrick? or server.trinidad?
times, chunks = [Time.now], []
server.get_stream do |chunk|
next if chunk.empty?
chunks << chunk
times << Time.now
end
assert_equal ["a", "b"], chunks
assert times[1] - times[0] < 1
assert times[2] - times[1] > 1
end
it 'streams async' do
next unless server.thin?
Timeout.timeout(3) do
chunks = []
server.get_stream '/async' do |chunk|
next if chunk.empty?
chunks << chunk
case chunk
when "hi!" then server.get "/send?msg=hello"
when "hello" then server.get "/send?close=1"
end
end
assert_equal ['hi!', 'hello'], chunks
end
end
it 'streams async from subclass' do
next unless server.thin?
Timeout.timeout(3) do
chunks = []
server.get_stream '/subclass/async' do |chunk|
next if chunk.empty?
chunks << chunk
case chunk
when "hi!" then server.get "/subclass/send?msg=hello"
when "hello" then server.get "/subclass/send?close=1"
end
end
assert_equal ['hi!', 'hello'], chunks
end
end
it 'starts the correct server' do
exp = %r{
==\sSinatra/#{Sinatra::VERSION}\s
has\staken\sthe\sstage\son\s\d+\sfor\sdevelopment\s
with\sbackup\sfrom\s#{server}
}ix
# because Net HTTP Server logs to $stderr by default
assert_match exp, server.log unless server.net_http_server?
end
it 'does not generate warnings' do
assert_raise(OpenURI::HTTPError) { server.get '/' }
server.get '/app_file'
assert_equal [], server.warnings
end
end sinatra-1.4.3/test/liquid_test.rb 0000644 0000041 0000041 00000003655 12161612727 017060 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
begin
require 'liquid'
class LiquidTest < Test::Unit::TestCase
def liquid_app(&block)
mock_app do
set :views, File.dirname(__FILE__) + '/views'
get('/', &block)
end
get '/'
end
it 'renders inline liquid strings' do
liquid_app { liquid 'Hiya
' }
assert ok?
assert_equal "Hiya
", body
end
it 'renders .liquid files in views path' do
liquid_app { liquid :hello }
assert ok?
assert_equal "Hello From Liquid
\n", body
end
it "renders with inline layouts" do
mock_app do
layout { "THIS. IS. {{ yield }}
" }
get('/') { liquid 'SPARTA' }
end
get '/'
assert ok?
assert_equal "THIS. IS. SPARTA
", body
end
it "renders with file layouts" do
liquid_app { liquid 'Hello World', :layout => :layout2 }
assert ok?
assert_equal "Liquid Layout!
\nHello World
\n", body
end
it "raises error if template not found" do
mock_app { get('/') { liquid :no_such_template } }
assert_raise(Errno::ENOENT) { get('/') }
end
it "allows passing locals" do
liquid_app {
liquid '{{ value }}', :locals => { :value => 'foo' }
}
assert ok?
assert_equal 'foo', body
end
it "can rendere truly nested layouts by accepting a layout and a block with the contents" do
mock_app do
template(:main_outer_layout) { "Title
\n{{ yield }}" }
template(:an_inner_layout) { "Subtitle
\n{{ yield }}" }
template(:a_page) { "Contents.
\n" }
get('/') do
liquid :main_outer_layout, :layout => false do
liquid :an_inner_layout do
liquid :a_page
end
end
end
end
get '/'
assert ok?
assert_body "Title
\nSubtitle
\nContents.
\n"
end
end
rescue LoadError
warn "#{$!.to_s}: skipping liquid tests"
end
sinatra-1.4.3/test/middleware_test.rb 0000644 0000041 0000041 00000003172 12161612727 017700 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
class MiddlewareTest < Test::Unit::TestCase
setup do
@app = mock_app(Sinatra::Application) do
get('/*')do
response.headers['X-Tests'] = env['test.ran'].
map { |n| n.split('::').last }.
join(', ')
env['PATH_INFO']
end
end
end
class MockMiddleware < Struct.new(:app)
def call(env)
(env['test.ran'] ||= []) << self.class.to_s
app.call(env)
end
end
class UpcaseMiddleware < MockMiddleware
def call(env)
env['PATH_INFO'] = env['PATH_INFO'].upcase
super
end
end
it "is added with Sinatra::Application.use" do
@app.use UpcaseMiddleware
get '/hello-world'
assert ok?
assert_equal '/HELLO-WORLD', body
end
class DowncaseMiddleware < MockMiddleware
def call(env)
env['PATH_INFO'] = env['PATH_INFO'].downcase
super
end
end
it "runs in the order defined" do
@app.use UpcaseMiddleware
@app.use DowncaseMiddleware
get '/Foo'
assert_equal "/foo", body
assert_equal "UpcaseMiddleware, DowncaseMiddleware", response['X-Tests']
end
it "resets the prebuilt pipeline when new middleware is added" do
@app.use UpcaseMiddleware
get '/Foo'
assert_equal "/FOO", body
@app.use DowncaseMiddleware
get '/Foo'
assert_equal '/foo', body
assert_equal "UpcaseMiddleware, DowncaseMiddleware", response['X-Tests']
end
it "works when app is used as middleware" do
@app.use UpcaseMiddleware
@app = @app.new
get '/Foo'
assert_equal "/FOO", body
assert_equal "UpcaseMiddleware", response['X-Tests']
end
end
sinatra-1.4.3/test/yajl_test.rb 0000644 0000041 0000041 00000003504 12161612727 016521 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
begin
require 'yajl'
class YajlTest < Test::Unit::TestCase
def yajl_app(&block)
mock_app do
set :views, File.dirname(__FILE__) + '/views'
get('/', &block)
end
get '/'
end
it 'renders inline Yajl strings' do
yajl_app { yajl('json = { :foo => "bar" }') }
assert ok?
assert_body '{"foo":"bar"}'
end
it 'renders .yajl files in views path' do
yajl_app { yajl(:hello) }
assert ok?
assert_body '{"yajl":"hello"}'
end
it 'raises error if template not found' do
mock_app { get('/') { yajl(:no_such_template) } }
assert_raise(Errno::ENOENT) { get('/') }
end
it 'accepts a :locals option' do
yajl_app do
locals = { :object => { :foo => 'bar' } }
yajl 'json = object', :locals => locals
end
assert ok?
assert_body '{"foo":"bar"}'
end
it 'accepts a :scope option' do
yajl_app do
scope = { :object => { :foo => 'bar' } }
yajl 'json = self[:object]', :scope => scope
end
assert ok?
assert_body '{"foo":"bar"}'
end
it 'decorates the json with a callback' do
yajl_app do
yajl(
'json = { :foo => "bar" }',
{ :callback => 'baz' }
)
end
assert ok?
assert_body 'baz({"foo":"bar"});'
end
it 'decorates the json with a variable' do
yajl_app do
yajl(
'json = { :foo => "bar" }',
{ :variable => 'qux' }
)
end
assert ok?
assert_body 'var qux = {"foo":"bar"};'
end
it 'decorates the json with a callback and a variable' do
yajl_app do
yajl(
'json = { :foo => "bar" }',
{ :callback => 'baz', :variable => 'qux' }
)
end
assert ok?
assert_body 'var qux = {"foo":"bar"}; baz(qux);'
end
end
rescue LoadError
warn "#{$!.to_s}: skipping yajl tests"
end
sinatra-1.4.3/test/sinatra_test.rb 0000644 0000041 0000041 00000000554 12161612727 017225 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
class SinatraTest < Test::Unit::TestCase
it 'creates a new Sinatra::Base subclass on new' do
app = Sinatra.new { get('/') { 'Hello World' } }
assert_same Sinatra::Base, app.superclass
end
it "responds to #template_cache" do
assert_kind_of Tilt::Cache, Sinatra::Base.new!.template_cache
end
end
sinatra-1.4.3/test/markaby_test.rb 0000644 0000041 0000041 00000003734 12161612727 017215 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
begin
require 'markaby'
class MarkabyTest < Test::Unit::TestCase
def markaby_app(&block)
mock_app do
set :views, File.dirname(__FILE__) + '/views'
get('/', &block)
end
get '/'
end
it 'renders inline markaby strings' do
markaby_app { markaby 'h1 "Hiya"' }
assert ok?
assert_equal "Hiya
", body
end
it 'renders .markaby files in views path' do
markaby_app { markaby :hello }
assert ok?
assert_equal "Hello From Markaby
", body
end
it "renders with inline layouts" do
mock_app do
layout { 'h1 { text "THIS. IS. "; yield }' }
get('/') { markaby 'em "SPARTA"' }
end
get '/'
assert ok?
assert_equal "THIS. IS. SPARTA
", body
end
it "renders with file layouts" do
markaby_app { markaby 'text "Hello World"', :layout => :layout2 }
assert ok?
assert_equal "Markaby Layout!
Hello World
", body
end
it 'renders inline markaby blocks' do
markaby_app { markaby { h1 'Hiya' } }
assert ok?
assert_equal "Hiya
", body
end
it 'renders inline markaby blocks with inline layouts' do
markaby_app do
settings.layout { 'h1 { text "THIS. IS. "; yield }' }
markaby { em 'SPARTA' }
end
assert ok?
assert_equal "THIS. IS. SPARTA
", body
end
it 'renders inline markaby blocks with file layouts' do
markaby_app { markaby(:layout => :layout2) { text "Hello World" } }
assert ok?
assert_equal "Markaby Layout!
Hello World
", body
end
it "raises error if template not found" do
mock_app { get('/') { markaby :no_such_template } }
assert_raise(Errno::ENOENT) { get('/') }
end
it "allows passing locals" do
markaby_app {
markaby 'text value', :locals => { :value => 'foo' }
}
assert ok?
assert_equal 'foo', body
end
end
rescue LoadError
warn "#{$!.to_s}: skipping markaby tests"
end
sinatra-1.4.3/test/helper.rb 0000644 0000041 0000041 00000006125 12161612727 016004 0 ustar www-data www-data ENV['RACK_ENV'] = 'test'
Encoding.default_external = "UTF-8" if defined? Encoding
RUBY_ENGINE = 'ruby' unless defined? RUBY_ENGINE
begin
require 'rack'
rescue LoadError
require 'rubygems'
require 'rack'
end
testdir = File.dirname(__FILE__)
$LOAD_PATH.unshift testdir unless $LOAD_PATH.include?(testdir)
libdir = File.dirname(File.dirname(__FILE__)) + '/lib'
$LOAD_PATH.unshift libdir unless $LOAD_PATH.include?(libdir)
require 'contest'
require 'rack/test'
require 'sinatra/base'
class Sinatra::Base
# Allow assertions in request context
include Test::Unit::Assertions
end
class Rack::Builder
def include?(middleware)
@ins.any? { |m| p m ; middleware === m }
end
end
Sinatra::Base.set :environment, :test
class Test::Unit::TestCase
include Rack::Test::Methods
class << self
alias_method :it, :test
alias_method :section, :context
end
def self.example(desc = nil, &block)
@example_count = 0 unless instance_variable_defined? :@example_count
@example_count += 1
it(desc || "Example #{@example_count}", &block)
end
alias_method :response, :last_response
setup do
Sinatra::Base.set :environment, :test
end
# Sets up a Sinatra::Base subclass defined with the block
# given. Used in setup or individual spec methods to establish
# the application.
def mock_app(base=Sinatra::Base, &block)
@app = Sinatra.new(base, &block)
end
def app
Rack::Lint.new(@app)
end
def body
response.body.to_s
end
def assert_body(value)
if value.respond_to? :to_str
assert_equal value.lstrip.gsub(/\s*\n\s*/, ""), body.lstrip.gsub(/\s*\n\s*/, "")
else
assert_match value, body
end
end
def assert_status(expected)
assert_equal Integer(expected), Integer(status)
end
def assert_like(a,b)
pattern = /id=['"][^"']*["']|\s+/
assert_equal a.strip.gsub(pattern, ""), b.strip.gsub(pattern, "")
end
def assert_include(str, substr)
assert str.include?(substr), "expected #{str.inspect} to include #{substr.inspect}"
end
def options(uri, params = {}, env = {}, &block)
request(uri, env.merge(:method => "OPTIONS", :params => params), &block)
end
def patch(uri, params = {}, env = {}, &block)
request(uri, env.merge(:method => "PATCH", :params => params), &block)
end
def link(uri, params = {}, env = {}, &block)
request(uri, env.merge(:method => "LINK", :params => params), &block)
end
def unlink(uri, params = {}, env = {}, &block)
request(uri, env.merge(:method => "UNLINK", :params => params), &block)
end
# Delegate other missing methods to response.
def method_missing(name, *args, &block)
if response && response.respond_to?(name)
response.send(name, *args, &block)
else
super
end
rescue Rack::Test::Error
super
end
# Also check response since we delegate there.
def respond_to?(symbol, include_private=false)
super || (response && response.respond_to?(symbol, include_private))
end
# Do not output warnings for the duration of the block.
def silence_warnings
$VERBOSE, v = nil, $VERBOSE
yield
ensure
$VERBOSE = v
end
end
sinatra-1.4.3/test/mapped_error_test.rb 0000644 0000041 0000041 00000016303 12161612727 020242 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
class FooError < RuntimeError
end
class FooNotFound < Sinatra::NotFound
end
class FooSpecialError < RuntimeError
def http_status; 501 end
end
class FooStatusOutOfRangeError < RuntimeError
def code; 4000 end
end
class FooWithCode < RuntimeError
def code; 419 end
end
class FirstError < RuntimeError; end
class SecondError < RuntimeError; end
class MappedErrorTest < Test::Unit::TestCase
def test_default
assert true
end
describe 'Exception Mappings' do
it 'invokes handlers registered with ::error when raised' do
mock_app do
set :raise_errors, false
error(FooError) { 'Foo!' }
get('/') { raise FooError }
end
get '/'
assert_equal 500, status
assert_equal 'Foo!', body
end
it 'passes the exception object to the error handler' do
mock_app do
set :raise_errors, false
error(FooError) { |e| assert_equal(FooError, e.class) }
get('/') { raise FooError }
end
get('/')
end
it 'uses the Exception handler if no matching handler found' do
mock_app do
set :raise_errors, false
error(Exception) { 'Exception!' }
get('/') { raise FooError }
end
get '/'
assert_equal 500, status
assert_equal 'Exception!', body
end
it 'walks down inheritance chain for errors' do
mock_app do
set :raise_errors, false
error(RuntimeError) { 'Exception!' }
get('/') { raise FooError }
end
get '/'
assert_equal 500, status
assert_equal 'Exception!', body
end
it 'favors subclass handler over superclass handler if available' do
mock_app do
set :raise_errors, false
error(Exception) { 'Exception!' }
error(FooError) { 'FooError!' }
error(RuntimeError) { 'Exception!' }
get('/') { raise FooError }
end
get '/'
assert_equal 500, status
assert_equal 'FooError!', body
end
it "sets env['sinatra.error'] to the rescued exception" do
mock_app do
set :raise_errors, false
error(FooError) do
assert env.include?('sinatra.error')
assert env['sinatra.error'].kind_of?(FooError)
'looks good'
end
get('/') { raise FooError }
end
get '/'
assert_equal 'looks good', body
end
it "raises errors from the app when raise_errors set and no handler defined" do
mock_app do
set :raise_errors, true
get('/') { raise FooError }
end
assert_raise(FooError) { get '/' }
end
it "calls error handlers before raising errors even when raise_errors is set" do
mock_app do
set :raise_errors, true
error(FooError) { "she's there." }
get('/') { raise FooError }
end
assert_nothing_raised { get '/' }
assert_equal 500, status
end
it "never raises Sinatra::NotFound beyond the application" do
mock_app(Sinatra::Application) do
get('/') { raise Sinatra::NotFound }
end
assert_nothing_raised { get '/' }
assert_equal 404, status
end
it "cascades for subclasses of Sinatra::NotFound" do
mock_app do
set :raise_errors, true
error(FooNotFound) { "foo! not found." }
get('/') { raise FooNotFound }
end
assert_nothing_raised { get '/' }
assert_equal 404, status
assert_equal 'foo! not found.', body
end
it 'has a not_found method for backwards compatibility' do
mock_app { not_found { "Lost, are we?" } }
get '/test'
assert_equal 404, status
assert_equal "Lost, are we?", body
end
it 'inherits error mappings from base class' do
base = Class.new(Sinatra::Base)
base.error(FooError) { 'base class' }
mock_app(base) do
set :raise_errors, false
get('/') { raise FooError }
end
get '/'
assert_equal 'base class', body
end
it 'overrides error mappings in base class' do
base = Class.new(Sinatra::Base)
base.error(FooError) { 'base class' }
mock_app(base) do
set :raise_errors, false
error(FooError) { 'subclass' }
get('/') { raise FooError }
end
get '/'
assert_equal 'subclass', body
end
it 'honors Exception#http_status if present' do
mock_app do
set :raise_errors, false
error(501) { 'Foo!' }
get('/') { raise FooSpecialError }
end
get '/'
assert_equal 501, status
assert_equal 'Foo!', body
end
it 'does not use Exception#code by default' do
mock_app do
set :raise_errors, false
get('/') { raise FooWithCode }
end
get '/'
assert_equal 500, status
end
it 'uses Exception#code if use_code is enabled' do
mock_app do
set :raise_errors, false
set :use_code, true
get('/') { raise FooWithCode }
end
get '/'
assert_equal 419, status
end
it 'does not rely on Exception#code for invalid codes' do
mock_app do
set :raise_errors, false
set :use_code, true
get('/') { raise FooStatusOutOfRangeError }
end
get '/'
assert_equal 500, status
end
it "allows a stack of exception_handlers" do
mock_app do
set :raise_errors, false
error(FirstError) { 'First!' }
error(SecondError) { 'Second!' }
get('/'){ raise SecondError }
end
get '/'
assert_equal 500, status
assert_equal 'Second!', body
end
it "allows an exception handler to pass control to the next exception handler" do
mock_app do
set :raise_errors, false
error(500, FirstError) { 'First!' }
error(500, SecondError) { pass }
get('/') { raise 500 }
end
get '/'
assert_equal 500, status
assert_equal 'First!', body
end
it "allows an exception handler to handle the exception" do
mock_app do
set :raise_errors, false
error(500, FirstError) { 'First!' }
error(500, SecondError) { 'Second!' }
get('/') { raise 500 }
end
get '/'
assert_equal 500, status
assert_equal 'Second!', body
end
end
describe 'Custom Error Pages' do
it 'allows numeric status code mappings to be registered with ::error' do
mock_app do
set :raise_errors, false
error(500) { 'Foo!' }
get('/') { [500, {}, 'Internal Foo Error'] }
end
get '/'
assert_equal 500, status
assert_equal 'Foo!', body
end
it 'allows ranges of status code mappings to be registered with :error' do
mock_app do
set :raise_errors, false
error(500..550) { "Error: #{response.status}" }
get('/') { [507, {}, 'A very special error'] }
end
get '/'
assert_equal 507, status
assert_equal 'Error: 507', body
end
it 'allows passing more than one range' do
mock_app do
set :raise_errors, false
error(409..411, 503..509) { "Error: #{response.status}" }
get('/') { [507, {}, 'A very special error'] }
end
get '/'
assert_equal 507, status
assert_equal 'Error: 507', body
end
end
end
sinatra-1.4.3/test/settings_test.rb 0000644 0000041 0000041 00000035572 12161612727 017434 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
class SettingsTest < Test::Unit::TestCase
setup do
@base = Sinatra.new(Sinatra::Base)
@base.set :environment => :foo, :app_file => nil
@application = Sinatra.new(Sinatra::Application)
@application.set :environment => :foo, :app_file => nil
end
it 'sets settings to literal values' do
@base.set(:foo, 'bar')
assert @base.respond_to?(:foo)
assert_equal 'bar', @base.foo
end
it 'sets settings to Procs' do
@base.set(:foo, Proc.new { 'baz' })
assert @base.respond_to?(:foo)
assert_equal 'baz', @base.foo
end
it 'sets settings using a block' do
@base.set(:foo){ 'baz' }
assert @base.respond_to?(:foo)
assert_equal 'baz', @base.foo
end
it 'raises an error with a value and a block' do
assert_raise ArgumentError do
@base.set(:fiz, 'boom!'){ 'baz' }
end
assert !@base.respond_to?(:fiz)
end
it 'raises an error without value and block' do
assert_raise(ArgumentError) { @base.set(:fiz) }
assert !@base.respond_to?(:fiz)
end
it 'allows setting a value to the app class' do
@base.set :base, @base
assert @base.respond_to?(:base)
assert_equal @base, @base.base
end
it 'raises an error with the app class as value and a block' do
assert_raise ArgumentError do
@base.set(:fiz, @base) { 'baz' }
end
assert !@base.respond_to?(:fiz)
end
it "sets multiple settings with a Hash" do
@base.set :foo => 1234,
:bar => 'Hello World',
:baz => Proc.new { 'bizzle' }
assert_equal 1234, @base.foo
assert_equal 'Hello World', @base.bar
assert_equal 'bizzle', @base.baz
end
it 'sets multiple settings using #each' do
@base.set [["foo", "bar"]]
assert_equal "bar", @base.foo
end
it 'inherits settings methods when subclassed' do
@base.set :foo, 'bar'
@base.set :biz, Proc.new { 'baz' }
sub = Class.new(@base)
assert sub.respond_to?(:foo)
assert_equal 'bar', sub.foo
assert sub.respond_to?(:biz)
assert_equal 'baz', sub.biz
end
it 'overrides settings in subclass' do
@base.set :foo, 'bar'
@base.set :biz, Proc.new { 'baz' }
sub = Class.new(@base)
sub.set :foo, 'bling'
assert_equal 'bling', sub.foo
assert_equal 'bar', @base.foo
end
it 'creates setter methods when first defined' do
@base.set :foo, 'bar'
assert @base.respond_to?('foo=')
@base.foo = 'biz'
assert_equal 'biz', @base.foo
end
it 'creates predicate methods when first defined' do
@base.set :foo, 'hello world'
assert @base.respond_to?(:foo?)
assert @base.foo?
@base.set :foo, nil
assert !@base.foo?
end
it 'uses existing setter methods if detected' do
class << @base
def foo
@foo
end
def foo=(value)
@foo = 'oops'
end
end
@base.set :foo, 'bam'
assert_equal 'oops', @base.foo
end
it 'merges values of multiple set calls if those are hashes' do
@base.set :foo, :a => 1
sub = Class.new(@base)
sub.set :foo, :b => 2
assert_equal({:a => 1, :b => 2}, sub.foo)
end
it 'merging does not affect the superclass' do
@base.set :foo, :a => 1
sub = Class.new(@base)
sub.set :foo, :b => 2
assert_equal({:a => 1}, @base.foo)
end
it 'is possible to change a value from a hash to something else' do
@base.set :foo, :a => 1
@base.set :foo, :bar
assert_equal(:bar, @base.foo)
end
it 'merges values with values of the superclass if those are hashes' do
@base.set :foo, :a => 1
@base.set :foo, :b => 2
assert_equal({:a => 1, :b => 2}, @base.foo)
end
it "sets multiple settings to true with #enable" do
@base.enable :sessions, :foo, :bar
assert @base.sessions
assert @base.foo
assert @base.bar
end
it "sets multiple settings to false with #disable" do
@base.disable :sessions, :foo, :bar
assert !@base.sessions
assert !@base.foo
assert !@base.bar
end
it 'is accessible from instances via #settings' do
assert_equal :foo, @base.new!.settings.environment
end
it 'is accessible from class via #settings' do
assert_equal :foo, @base.settings.environment
end
describe 'methodoverride' do
it 'is disabled on Base' do
assert ! @base.method_override?
end
it 'is enabled on Application' do
assert @application.method_override?
end
it 'enables MethodOverride middleware' do
@base.set :method_override, true
@base.put('/') { 'okay' }
@app = @base
post '/', {'_method'=>'PUT'}, {}
assert_equal 200, status
assert_equal 'okay', body
end
it 'is backward compatible with methodoverride' do
assert ! @base.methodoverride?
@base.enable :methodoverride
assert @base.methodoverride?
end
end
describe 'run' do
it 'is disabled on Base' do
assert ! @base.run?
end
it 'is enabled on Application except in test environment' do
assert @application.run?
@application.set :environment, :test
assert ! @application.run?
end
end
describe 'raise_errors' do
it 'is enabled on Base only in test' do
assert ! @base.raise_errors?
@base.set(:environment, :test)
assert @base.raise_errors?
end
it 'is enabled on Application only in test' do
assert ! @application.raise_errors?
@application.set(:environment, :test)
assert @application.raise_errors?
end
end
describe 'show_exceptions' do
it 'is disabled on Base except under development' do
assert ! @base.show_exceptions?
@base.environment = :development
assert @base.show_exceptions?
end
it 'is disabled on Application except in development' do
assert ! @application.show_exceptions?
@application.set(:environment, :development)
assert @application.show_exceptions?
end
it 'returns a friendly 500' do
klass = Sinatra.new(Sinatra::Application)
mock_app(klass) {
enable :show_exceptions
get '/' do
raise StandardError
end
}
get '/'
assert_equal 500, status
assert body.include?("StandardError")
assert body.include?("show_exceptions
setting")
end
it 'does not override app-specified error handling when set to :after_handler' do
ran = false
mock_app do
set :show_exceptions, :after_handler
error(RuntimeError) { ran = true }
get('/') { raise RuntimeError }
end
get '/'
assert_equal 500, status
assert ran
end
it 'does catch any other exceptions when set to :after_handler' do
ran = false
mock_app do
set :show_exceptions, :after_handler
error(RuntimeError) { ran = true }
get('/') { raise ArgumentError }
end
get '/'
assert_equal 500, status
assert !ran
end
end
describe 'dump_errors' do
it 'is disabled on Base in test' do
@base.environment = :test
assert ! @base.dump_errors?
@base.environment = :development
assert @base.dump_errors?
@base.environment = :production
assert @base.dump_errors?
end
it 'dumps exception with backtrace to rack.errors' do
klass = Sinatra.new(Sinatra::Application)
mock_app(klass) {
enable :dump_errors
disable :raise_errors
error do
error = @env['rack.errors'].instance_variable_get(:@error)
error.rewind
error.read
end
get '/' do
raise
end
}
get '/'
assert body.include?("RuntimeError") && body.include?("settings_test.rb")
end
it 'does not dump 404 errors' do
klass = Sinatra.new(Sinatra::Application)
mock_app(klass) {
enable :dump_errors
disable :raise_errors
error do
error = @env['rack.errors'].instance_variable_get(:@error)
error.rewind
error.read
end
get '/' do
raise Sinatra::NotFound
end
}
get '/'
assert !body.include?("NotFound") && !body.include?("settings_test.rb")
end
end
describe 'sessions' do
it 'is disabled on Base' do
assert ! @base.sessions?
end
it 'is disabled on Application' do
assert ! @application.sessions?
end
end
describe 'logging' do
it 'is disabled on Base' do
assert ! @base.logging?
end
it 'is enabled on Application except in test environment' do
assert @application.logging?
@application.set :environment, :test
assert ! @application.logging
end
end
describe 'static' do
it 'is disabled on Base by default' do
assert ! @base.static?
end
it 'is enabled on Base when public_folder is set and exists' do
@base.set :environment, :development
@base.set :public_folder, File.dirname(__FILE__)
assert @base.static?
end
it 'is enabled on Base when root is set and root/public_folder exists' do
@base.set :environment, :development
@base.set :root, File.dirname(__FILE__)
assert @base.static?
end
it 'is disabled on Application by default' do
assert ! @application.static?
end
it 'is enabled on Application when public_folder is set and exists' do
@application.set :environment, :development
@application.set :public_folder, File.dirname(__FILE__)
assert @application.static?
end
it 'is enabled on Application when root is set and root/public_folder exists' do
@application.set :environment, :development
@application.set :root, File.dirname(__FILE__)
assert @application.static?
end
it 'is possible to use Module#public' do
@base.send(:define_method, :foo) { }
@base.send(:private, :foo)
assert !@base.public_method_defined?(:foo)
@base.send(:public, :foo)
assert @base.public_method_defined?(:foo)
end
it 'is possible to use the keyword public in a sinatra app' do
app = Sinatra.new do
private
def priv; end
public
def pub; end
end
assert !app.public_method_defined?(:priv)
assert app.public_method_defined?(:pub)
end
end
describe 'bind' do
it 'defaults to 0.0.0.0' do
assert_equal '0.0.0.0', @base.bind
assert_equal '0.0.0.0', @application.bind
end
end
describe 'port' do
it 'defaults to 4567' do
assert_equal 4567, @base.port
assert_equal 4567, @application.port
end
end
describe 'server' do
it 'includes webrick' do
assert @base.server.include?('webrick')
assert @application.server.include?('webrick')
end
it 'includes puma' do
assert @base.server.include?('puma')
assert @application.server.include?('puma')
end
it 'includes thin' do
next if RUBY_ENGINE == 'jruby'
assert @base.server.include?('thin')
assert @application.server.include?('thin')
end
end
describe 'app_file' do
it 'is nil for base classes' do
assert_nil Sinatra::Base.app_file
assert_nil Sinatra::Application.app_file
end
it 'defaults to the file subclassing' do
assert_equal File.expand_path(__FILE__), Sinatra.new.app_file
end
end
describe 'root' do
it 'is nil if app_file is not set' do
assert @base.root.nil?
assert @application.root.nil?
end
it 'is equal to the expanded basename of app_file' do
@base.app_file = __FILE__
assert_equal File.expand_path(File.dirname(__FILE__)), @base.root
@application.app_file = __FILE__
assert_equal File.expand_path(File.dirname(__FILE__)), @application.root
end
end
describe 'views' do
it 'is nil if root is not set' do
assert @base.views.nil?
assert @application.views.nil?
end
it 'is set to root joined with views/' do
@base.root = File.dirname(__FILE__)
assert_equal File.dirname(__FILE__) + "/views", @base.views
@application.root = File.dirname(__FILE__)
assert_equal File.dirname(__FILE__) + "/views", @application.views
end
end
describe 'public_folder' do
it 'is nil if root is not set' do
assert @base.public_folder.nil?
assert @application.public_folder.nil?
end
it 'is set to root joined with public/' do
@base.root = File.dirname(__FILE__)
assert_equal File.dirname(__FILE__) + "/public", @base.public_folder
@application.root = File.dirname(__FILE__)
assert_equal File.dirname(__FILE__) + "/public", @application.public_folder
end
end
describe 'public_dir' do
it 'is an alias for public_folder' do
@base.public_dir = File.dirname(__FILE__)
assert_equal File.dirname(__FILE__), @base.public_dir
assert_equal @base.public_folder, @base.public_dir
@application.public_dir = File.dirname(__FILE__)
assert_equal File.dirname(__FILE__), @application.public_dir
assert_equal @application.public_folder, @application.public_dir
end
end
describe 'lock' do
it 'is disabled by default' do
assert ! @base.lock?
assert ! @application.lock?
end
end
describe 'protection' do
class MiddlewareTracker < Rack::Builder
def self.track
Rack.send :remove_const, :Builder
Rack.const_set :Builder, MiddlewareTracker
MiddlewareTracker.used.clear
yield
ensure
Rack.send :remove_const, :Builder
Rack.const_set :Builder, MiddlewareTracker.superclass
end
def self.used
@used ||= []
end
def use(middleware, *)
MiddlewareTracker.used << middleware
super
end
end
it 'sets up Rack::Protection' do
MiddlewareTracker.track do
Sinatra::Base.new
assert_include MiddlewareTracker.used, Rack::Protection
end
end
it 'sets up Rack::Protection::PathTraversal' do
MiddlewareTracker.track do
Sinatra::Base.new
assert_include MiddlewareTracker.used, Rack::Protection::PathTraversal
end
end
it 'does not set up Rack::Protection::PathTraversal when disabling it' do
MiddlewareTracker.track do
Sinatra.new { set :protection, :except => :path_traversal }.new
assert_include MiddlewareTracker.used, Rack::Protection
assert !MiddlewareTracker.used.include?(Rack::Protection::PathTraversal)
end
end
it 'sets up RemoteToken if sessions are enabled' do
MiddlewareTracker.track do
Sinatra.new { enable :sessions }.new
assert_include MiddlewareTracker.used, Rack::Protection::RemoteToken
end
end
it 'does not set up RemoteToken if sessions are disabled' do
MiddlewareTracker.track do
Sinatra.new.new
assert !MiddlewareTracker.used.include?(Rack::Protection::RemoteToken)
end
end
it 'sets up RemoteToken if it is configured to' do
MiddlewareTracker.track do
Sinatra.new { set :protection, :session => true }.new
assert_include MiddlewareTracker.used, Rack::Protection::RemoteToken
end
end
end
end
sinatra-1.4.3/test/less_test.rb 0000644 0000041 0000041 00000003475 12161612727 016537 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
begin
require 'less'
class LessTest < Test::Unit::TestCase
def less_app(options = {}, &block)
mock_app do
set :views, File.dirname(__FILE__) + '/views'
set options
get('/', &block)
end
get '/'
end
it 'renders inline Less strings' do
less_app {
less "@white_color: #fff; #main { background-color: @white_color }"
}
assert ok?
assert_equal "#main{background-color:#ffffff;}", body.gsub(/\s/, "")
end
it 'defaults content type to css' do
less_app {
less "@white_color: #fff; #main { background-color: @white_color }"
}
assert ok?
assert_equal "text/css;charset=utf-8", response['Content-Type']
end
it 'defaults allows setting content type per route' do
less_app do
content_type :html
less "@white_color: #fff; #main { background-color: @white_color }"
end
assert ok?
assert_equal "text/html;charset=utf-8", response['Content-Type']
end
it 'defaults allows setting content type globally' do
less_app(:less => { :content_type => 'html' }) do
less "@white_color: #fff; #main { background-color: @white_color }"
end
assert ok?
assert_equal "text/html;charset=utf-8", response['Content-Type']
end
it 'renders .less files in views path' do
less_app { less :hello }
assert ok?
assert_equal "#main{background-color:#ffffff;}", body.gsub(/\s/, "")
end
it 'ignores the layout option' do
less_app { less :hello, :layout => :layout2 }
assert ok?
assert_equal "#main{background-color:#ffffff;}", body.gsub(/\s/, "")
end
it "raises error if template not found" do
mock_app { get('/') { less :no_such_template } }
assert_raise(Errno::ENOENT) { get('/') }
end
end
rescue LoadError
warn "#{$!.to_s}: skipping less tests"
end
sinatra-1.4.3/test/markdown_test.rb 0000644 0000041 0000041 00000004032 12161612727 017401 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
MarkdownTest = proc do
def markdown_app(&block)
mock_app do
set :views, File.dirname(__FILE__) + '/views'
get('/', &block)
end
get '/'
end
def setup
Tilt.prefer engine, 'markdown', 'mkd', 'md'
super
end
it 'uses the correct engine' do
assert_equal engine, Tilt[:md]
assert_equal engine, Tilt[:mkd]
assert_equal engine, Tilt[:markdown]
end
it 'renders inline markdown strings' do
markdown_app { markdown '# Hiya' }
assert ok?
assert_like "Hiya
\n", body
end
it 'renders .markdown files in views path' do
markdown_app { markdown :hello }
assert ok?
assert_like "Hello From Markdown
", body
end
it "raises error if template not found" do
mock_app { get('/') { markdown :no_such_template } }
assert_raise(Errno::ENOENT) { get('/') }
end
it "renders with inline layouts" do
mock_app do
layout { 'THIS. IS. #{yield.upcase}!' }
get('/') { markdown 'Sparta', :layout_engine => :str }
end
get '/'
assert ok?
assert_like 'THIS. IS. SPARTA
!', body
end
it "renders with file layouts" do
markdown_app {
markdown 'Hello World', :layout => :layout2, :layout_engine => :erb
}
assert ok?
assert_body "ERB Layout!\nHello World
"
end
it "can be used in a nested fashion for partials and whatnot" do
mock_app do
template(:inner) { "hi" }
template(:outer) { "<%= markdown :inner %>" }
get('/') { erb :outer }
end
get '/'
assert ok?
assert_like 'hi
', body
end
end
# Will generate RDiscountTest, KramdownTest, etc.
Tilt.mappings['md'].each do |t|
begin
t.new { "" }
klass = Class.new(Test::Unit::TestCase) { define_method(:engine) { t }}
klass.class_eval(&MarkdownTest)
name = t.name[/[^:]+$/].sub(/Template$/, '') << "Test"
Object.const_set name, klass
rescue LoadError, NameError
warn "#{$!}: skipping markdown tests with #{t}"
end
end
sinatra-1.4.3/test/routing_test.rb 0000644 0000041 0000041 00000077455 12161612727 017271 0 ustar www-data www-data # I like coding: UTF-8
require File.expand_path('../helper', __FILE__)
# Helper method for easy route pattern matching testing
def route_def(pattern)
mock_app { get(pattern) { } }
end
class RegexpLookAlike
class MatchData
def captures
["this", "is", "a", "test"]
end
end
def match(string)
::RegexpLookAlike::MatchData.new if string == "/this/is/a/test/"
end
def keys
["one", "two", "three", "four"]
end
end
class RoutingTest < Test::Unit::TestCase
%w[get put post delete options patch link unlink].each do |verb|
it "defines #{verb.upcase} request handlers with #{verb}" do
mock_app {
send verb, '/hello' do
'Hello World'
end
}
request = Rack::MockRequest.new(@app)
response = request.request(verb.upcase, '/hello', {})
assert response.ok?
assert_equal 'Hello World', response.body
end
end
it "defines HEAD request handlers with HEAD" do
mock_app {
head '/hello' do
response['X-Hello'] = 'World!'
'remove me'
end
}
request = Rack::MockRequest.new(@app)
response = request.request('HEAD', '/hello', {})
assert response.ok?
assert_equal 'World!', response['X-Hello']
assert_equal '', response.body
end
it "404s when no route satisfies the request" do
mock_app {
get('/foo') { }
}
get '/bar'
assert_equal 404, status
end
it "404s and sets X-Cascade header when no route satisfies the request" do
mock_app {
get('/foo') { }
}
get '/bar'
assert_equal 404, status
assert_equal 'pass', response.headers['X-Cascade']
end
it "404s and does not set X-Cascade header when no route satisfies the request and x_cascade has been disabled" do
mock_app {
disable :x_cascade
get('/foo') { }
}
get '/bar'
assert_equal 404, status
assert_equal nil, response.headers['X-Cascade']
end
it "allows using unicode" do
mock_app do
get('/föö') { }
end
get '/f%C3%B6%C3%B6'
assert_equal 200, status
end
it "it handles encoded slashes correctly" do
mock_app { get("/:a") { |a| a } }
get '/foo%2Fbar'
assert_equal 200, status
assert_body "foo/bar"
end
it "overrides the content-type in error handlers" do
mock_app {
before { content_type 'text/plain' }
error Sinatra::NotFound do
content_type "text/html"
"Not Found
"
end
}
get '/foo'
assert_equal 404, status
assert_equal 'text/html;charset=utf-8', response["Content-Type"]
assert_equal "Not Found
", response.body
end
it "recalculates body length correctly for 404 response" do
mock_app {
get '/' do
@response["Content-Length"] = "30"
raise Sinatra::NotFound
end
}
get "/"
assert_equal "18", response["Content-Length"]
assert_equal 404, status
end
it 'matches empty PATH_INFO to "/" if no route is defined for ""' do
mock_app do
get '/' do
'worked'
end
end
get '/', {}, "PATH_INFO" => ""
assert ok?
assert_equal 'worked', body
end
it 'matches empty PATH_INFO to "" if a route is defined for ""' do
mock_app do
disable :protection
get '/' do
'did not work'
end
get '' do
'worked'
end
end
get '/', {}, "PATH_INFO" => ""
assert ok?
assert_equal 'worked', body
end
it 'takes multiple definitions of a route' do
mock_app {
user_agent(/Foo/)
get '/foo' do
'foo'
end
get '/foo' do
'not foo'
end
}
get '/foo', {}, 'HTTP_USER_AGENT' => 'Foo'
assert ok?
assert_equal 'foo', body
get '/foo'
assert ok?
assert_equal 'not foo', body
end
it "exposes params with indifferent hash" do
mock_app {
get '/:foo' do
assert_equal 'bar', params['foo']
assert_equal 'bar', params[:foo]
'well, alright'
end
}
get '/bar'
assert_equal 'well, alright', body
end
it "merges named params and query string params in params" do
mock_app {
get '/:foo' do
assert_equal 'bar', params['foo']
assert_equal 'biz', params['baz']
end
}
get '/bar?baz=biz'
assert ok?
end
it "supports named params like /hello/:person" do
mock_app {
get '/hello/:person' do
"Hello #{params['person']}"
end
}
get '/hello/Frank'
assert_equal 'Hello Frank', body
end
it "supports optional named params like /?:foo?/?:bar?" do
mock_app {
get '/?:foo?/?:bar?' do
"foo=#{params[:foo]};bar=#{params[:bar]}"
end
}
get '/hello/world'
assert ok?
assert_equal "foo=hello;bar=world", body
get '/hello'
assert ok?
assert_equal "foo=hello;bar=", body
get '/'
assert ok?
assert_equal "foo=;bar=", body
end
it "supports named captures like %r{/hello/(?[^/?#]+)} on Ruby >= 1.9" do
next if RUBY_VERSION < '1.9'
mock_app {
get Regexp.new('/hello/(?[^/?#]+)') do
"Hello #{params['person']}"
end
}
get '/hello/Frank'
assert_equal 'Hello Frank', body
end
it "supports optional named captures like %r{/page(?.[^/?#]+)?} on Ruby >= 1.9" do
next if RUBY_VERSION < '1.9'
mock_app {
get Regexp.new('/page(?.[^/?#]+)?') do
"format=#{params[:format]}"
end
}
get '/page.html'
assert ok?
assert_equal "format=.html", body
get '/page.xml'
assert ok?
assert_equal "format=.xml", body
get '/page'
assert ok?
assert_equal "format=", body
end
it 'does not concatinate params with the same name' do
mock_app { get('/:foo') { params[:foo] } }
get '/a?foo=b'
assert_body 'a'
end
it "supports single splat params like /*" do
mock_app {
get '/*' do
assert params['splat'].kind_of?(Array)
params['splat'].join "\n"
end
}
get '/foo'
assert_equal "foo", body
get '/foo/bar/baz'
assert_equal "foo/bar/baz", body
end
it "supports mixing multiple splat params like /*/foo/*/*" do
mock_app {
get '/*/foo/*/*' do
assert params['splat'].kind_of?(Array)
params['splat'].join "\n"
end
}
get '/bar/foo/bling/baz/boom'
assert_equal "bar\nbling\nbaz/boom", body
get '/bar/foo/baz'
assert not_found?
end
it "supports mixing named and splat params like /:foo/*" do
mock_app {
get '/:foo/*' do
assert_equal 'foo', params['foo']
assert_equal ['bar/baz'], params['splat']
end
}
get '/foo/bar/baz'
assert ok?
end
it "matches a dot ('.') as part of a named param" do
mock_app {
get '/:foo/:bar' do
params[:foo]
end
}
get '/user@example.com/name'
assert_equal 200, response.status
assert_equal 'user@example.com', body
end
it "matches a literal dot ('.') outside of named params" do
mock_app {
get '/:file.:ext' do
assert_equal 'pony', params[:file]
assert_equal 'jpg', params[:ext]
'right on'
end
}
get '/pony.jpg'
assert_equal 200, response.status
assert_equal 'right on', body
end
it "literally matches dot in paths" do
route_def '/test.bar'
get '/test.bar'
assert ok?
get 'test0bar'
assert not_found?
end
it "literally matches dollar sign in paths" do
route_def '/test$/'
get '/test$/'
assert ok?
end
it "literally matches plus sign in paths" do
route_def '/te+st/'
get '/te%2Bst/'
assert ok?
get '/teeeeeeest/'
assert not_found?
end
it "does not convert plus sign into space as the value of a named param" do
mock_app do
get '/:test' do
params["test"]
end
end
get '/bob+ross'
assert ok?
assert_equal 'bob+ross', body
end
it "literally matches parens in paths" do
route_def '/test(bar)/'
get '/test(bar)/'
assert ok?
end
it "supports basic nested params" do
mock_app {
get '/hi' do
params["person"]["name"]
end
}
get "/hi?person[name]=John+Doe"
assert ok?
assert_equal "John Doe", body
end
it "exposes nested params with indifferent hash" do
mock_app {
get '/testme' do
assert_equal 'baz', params['bar']['foo']
assert_equal 'baz', params['bar'][:foo]
'well, alright'
end
}
get '/testme?bar[foo]=baz'
assert_equal 'well, alright', body
end
it "exposes params nested within arrays with indifferent hash" do
mock_app {
get '/testme' do
assert_equal 'baz', params['bar'][0]['foo']
assert_equal 'baz', params['bar'][0][:foo]
'well, alright'
end
}
get '/testme?bar[][foo]=baz'
assert_equal 'well, alright', body
end
it "supports arrays within params" do
mock_app {
get '/foo' do
assert_equal ['A', 'B'], params['bar']
'looks good'
end
}
get '/foo?bar[]=A&bar[]=B'
assert ok?
assert_equal 'looks good', body
end
it "supports deeply nested params" do
expected_params = {
"emacs" => {
"map" => { "goto-line" => "M-g g" },
"version" => "22.3.1"
},
"browser" => {
"firefox" => {"engine" => {"name"=>"spidermonkey", "version"=>"1.7.0"}},
"chrome" => {"engine" => {"name"=>"V8", "version"=>"1.0"}}
},
"paste" => {"name"=>"hello world", "syntax"=>"ruby"}
}
mock_app {
get '/foo' do
assert_equal expected_params, params
'looks good'
end
}
get '/foo', expected_params
assert ok?
assert_equal 'looks good', body
end
it "preserves non-nested params" do
mock_app {
get '/foo' do
assert_equal "2", params["article_id"]
assert_equal "awesome", params['comment']['body']
assert_nil params['comment[body]']
'looks good'
end
}
get '/foo?article_id=2&comment[body]=awesome'
assert ok?
assert_equal 'looks good', body
end
it "matches paths that include spaces encoded with %20" do
mock_app {
get '/path with spaces' do
'looks good'
end
}
get '/path%20with%20spaces'
assert ok?
assert_equal 'looks good', body
end
it "matches paths that include spaces encoded with +" do
mock_app {
get '/path with spaces' do
'looks good'
end
}
get '/path+with+spaces'
assert ok?
assert_equal 'looks good', body
end
it "matches paths that include ampersands" do
mock_app {
get '/:name' do
'looks good'
end
}
get '/foo&bar'
assert ok?
assert_equal 'looks good', body
end
it "URL decodes named parameters and splats" do
mock_app {
get '/:foo/*' do
assert_equal 'hello world', params['foo']
assert_equal ['how are you'], params['splat']
nil
end
}
get '/hello%20world/how%20are%20you'
assert ok?
end
it 'supports regular expressions' do
mock_app {
get(/^\/foo...\/bar$/) do
'Hello World'
end
}
get '/foooom/bar'
assert ok?
assert_equal 'Hello World', body
end
it 'makes regular expression captures available in params[:captures]' do
mock_app {
get(/^\/fo(.*)\/ba(.*)/) do
assert_equal ['orooomma', 'f'], params[:captures]
'right on'
end
}
get '/foorooomma/baf'
assert ok?
assert_equal 'right on', body
end
it 'supports regular expression look-alike routes' do
mock_app {
get(RegexpLookAlike.new) do
assert_equal 'this', params[:one]
assert_equal 'is', params[:two]
assert_equal 'a', params[:three]
assert_equal 'test', params[:four]
'right on'
end
}
get '/this/is/a/test/'
assert ok?
assert_equal 'right on', body
end
it 'raises a TypeError when pattern is not a String or Regexp' do
assert_raise(TypeError) {
mock_app { get(42){} }
}
end
it "returns response immediately on halt" do
mock_app {
get '/' do
halt 'Hello World'
'Boo-hoo World'
end
}
get '/'
assert ok?
assert_equal 'Hello World', body
end
it "halts with a response tuple" do
mock_app {
get '/' do
halt 295, {'Content-Type' => 'text/plain'}, 'Hello World'
end
}
get '/'
assert_equal 295, status
assert_equal 'text/plain', response['Content-Type']
assert_equal 'Hello World', body
end
it "halts with an array of strings" do
mock_app {
get '/' do
halt %w[Hello World How Are You]
end
}
get '/'
assert_equal 'HelloWorldHowAreYou', body
end
it 'sets response.status with halt' do
status_was = nil
mock_app do
after { status_was = status }
get('/') { halt 500, 'error' }
end
get '/'
assert_status 500
assert_equal 500, status_was
end
it "transitions to the next matching route on pass" do
mock_app {
get '/:foo' do
pass
'Hello Foo'
end
get '/*' do
assert !params.include?('foo')
'Hello World'
end
}
get '/bar'
assert ok?
assert_equal 'Hello World', body
end
it "transitions to 404 when passed and no subsequent route matches" do
mock_app {
get '/:foo' do
pass
'Hello Foo'
end
}
get '/bar'
assert not_found?
end
it "transitions to 404 and sets X-Cascade header when passed and no subsequent route matches" do
mock_app {
get '/:foo' do
pass
'Hello Foo'
end
get '/bar' do
'Hello Bar'
end
}
get '/foo'
assert not_found?
assert_equal 'pass', response.headers['X-Cascade']
end
it "uses optional block passed to pass as route block if no other route is found" do
mock_app {
get "/" do
pass do
"this"
end
"not this"
end
}
get "/"
assert ok?
assert "this", body
end
it "passes when matching condition returns false" do
mock_app {
condition { params[:foo] == 'bar' }
get '/:foo' do
'Hello World'
end
}
get '/bar'
assert ok?
assert_equal 'Hello World', body
get '/foo'
assert not_found?
end
it "does not pass when matching condition returns nil" do
mock_app {
condition { nil }
get '/:foo' do
'Hello World'
end
}
get '/bar'
assert ok?
assert_equal 'Hello World', body
end
it "passes to next route when condition calls pass explicitly" do
mock_app {
condition { pass unless params[:foo] == 'bar' }
get '/:foo' do
'Hello World'
end
}
get '/bar'
assert ok?
assert_equal 'Hello World', body
get '/foo'
assert not_found?
end
it "passes to the next route when host_name does not match" do
mock_app {
host_name 'example.com'
get '/foo' do
'Hello World'
end
}
get '/foo'
assert not_found?
get '/foo', {}, { 'HTTP_HOST' => 'example.com' }
assert_equal 200, status
assert_equal 'Hello World', body
end
it "passes to the next route when user_agent does not match" do
mock_app {
user_agent(/Foo/)
get '/foo' do
'Hello World'
end
}
get '/foo'
assert not_found?
get '/foo', {}, { 'HTTP_USER_AGENT' => 'Foo Bar' }
assert_equal 200, status
assert_equal 'Hello World', body
end
it "treats missing user agent like an empty string" do
mock_app do
user_agent(/.*/)
get '/' do
"Hello World"
end
end
get '/'
assert_equal 200, status
assert_equal 'Hello World', body
end
it "makes captures in user agent pattern available in params[:agent]" do
mock_app {
user_agent(/Foo (.*)/)
get '/foo' do
'Hello ' + params[:agent].first
end
}
get '/foo', {}, { 'HTTP_USER_AGENT' => 'Foo Bar' }
assert_equal 200, status
assert_equal 'Hello Bar', body
end
it 'matches mime_types with dots, hyphens and plus signs' do
mime_types = %w(
application/atom+xml
application/ecmascript
application/EDI-X12
application/EDIFACT
application/json
application/javascript
application/octet-stream
application/ogg
application/pdf
application/postscript
application/rdf+xml
application/rss+xml
application/soap+xml
application/font-woff
application/xhtml+xml
application/xml
application/xml-dtd
application/xop+xml
application/zip
application/gzip
audio/basic
audio/L24
audio/mp4
audio/mpeg
audio/ogg
audio/vorbis
audio/vnd.rn-realaudio
audio/vnd.wave
audio/webm
image/gif
image/jpeg
image/pjpeg
image/png
image/svg+xml
image/tiff
image/vnd.microsoft.icon
message/http
message/imdn+xml
message/partial
message/rfc822
model/example
model/iges
model/mesh
model/vrml
model/x3d+binary
model/x3d+vrml
model/x3d+xml
multipart/mixed
multipart/alternative
multipart/related
multipart/form-data
multipart/signed
multipart/encrypted
text/cmd
text/css
text/csv
text/html
text/javascript
application/javascript
text/plain
text/vcard
text/xml
video/mpeg
video/mp4
video/ogg
video/quicktime
video/webm
video/x-matroska
video/x-ms-wmv
video/x-flv
application/vnd.oasis.opendocument.text
application/vnd.oasis.opendocument.spreadsheet
application/vnd.oasis.opendocument.presentation
application/vnd.oasis.opendocument.graphics
application/vnd.ms-excel
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
application/vnd.ms-powerpoint
application/vnd.openxmlformats-officedocument.presentationml.presentation
application/vnd.openxmlformats-officedocument.wordprocessingml.document
application/vnd.mozilla.xul+xml
application/vnd.google-earth.kml+xml
application/x-deb
application/x-dvi
application/x-font-ttf
application/x-javascript
application/x-latex
application/x-mpegURL
application/x-rar-compressed
application/x-shockwave-flash
application/x-stuffit
application/x-tar
application/x-www-form-urlencoded
application/x-xpinstall
audio/x-aac
audio/x-caf
image/x-xcf
text/x-gwt-rpc
text/x-jquery-tmpl
application/x-pkcs12
application/x-pkcs12
application/x-pkcs7-certificates
application/x-pkcs7-certificates
application/x-pkcs7-certreqresp
application/x-pkcs7-mime
application/x-pkcs7-mime
application/x-pkcs7-signature
)
mime_types.each { |mime_type| assert mime_type.match(Sinatra::Request::HEADER_VALUE_WITH_PARAMS) }
end
it "filters by accept header" do
mock_app {
get '/', :provides => :xml do
env['HTTP_ACCEPT']
end
get '/foo', :provides => :html do
env['HTTP_ACCEPT']
end
get '/stream', :provides => 'text/event-stream' do
env['HTTP_ACCEPT']
end
}
get '/', {}, { 'HTTP_ACCEPT' => 'application/xml' }
assert ok?
assert_equal 'application/xml', body
assert_equal 'application/xml;charset=utf-8', response.headers['Content-Type']
get '/', {}, {}
assert ok?
assert_equal '', body
assert_equal 'application/xml;charset=utf-8', response.headers['Content-Type']
get '/', {}, { 'HTTP_ACCEPT' => '*/*' }
assert ok?
assert_equal '*/*', body
assert_equal 'application/xml;charset=utf-8', response.headers['Content-Type']
get '/', {}, { 'HTTP_ACCEPT' => 'text/html;q=0.9' }
assert !ok?
get '/foo', {}, { 'HTTP_ACCEPT' => 'text/html;q=0.9' }
assert ok?
assert_equal 'text/html;q=0.9', body
get '/foo', {}, { 'HTTP_ACCEPT' => '' }
assert ok?
assert_equal '', body
get '/foo', {}, { 'HTTP_ACCEPT' => '*/*' }
assert ok?
assert_equal '*/*', body
get '/foo', {}, { 'HTTP_ACCEPT' => 'application/xml' }
assert !ok?
get '/stream', {}, { 'HTTP_ACCEPT' => 'text/event-stream' }
assert ok?
assert_equal 'text/event-stream', body
get '/stream', {}, { 'HTTP_ACCEPT' => '' }
assert ok?
assert_equal '', body
get '/stream', {}, { 'HTTP_ACCEPT' => '*/*' }
assert ok?
assert_equal '*/*', body
get '/stream', {}, { 'HTTP_ACCEPT' => 'application/xml' }
assert !ok?
end
it "filters by current Content-Type" do
mock_app do
before('/txt') { content_type :txt }
get('*', :provides => :txt) { 'txt' }
before('/html') { content_type :html }
get('*', :provides => :html) { 'html' }
end
get '/', {}, { 'HTTP_ACCEPT' => '*/*' }
assert ok?
assert_equal 'text/plain;charset=utf-8', response.headers['Content-Type']
assert_body 'txt'
get '/txt', {}, { 'HTTP_ACCEPT' => 'text/plain' }
assert ok?
assert_equal 'text/plain;charset=utf-8', response.headers['Content-Type']
assert_body 'txt'
get '/', {}, { 'HTTP_ACCEPT' => 'text/html' }
assert ok?
assert_equal 'text/html;charset=utf-8', response.headers['Content-Type']
assert_body 'html'
end
it "allows multiple mime types for accept header" do
types = ['image/jpeg', 'image/pjpeg']
mock_app {
get '/', :provides => types do
env['HTTP_ACCEPT']
end
}
types.each do |type|
get '/', {}, { 'HTTP_ACCEPT' => type }
assert ok?
assert_equal type, body
assert_equal type, response.headers['Content-Type']
end
end
it 'respects user agent preferences for the content type' do
mock_app { get('/', :provides => [:png, :html]) { content_type }}
get '/', {}, { 'HTTP_ACCEPT' => 'image/png;q=0.5,text/html;q=0.8' }
assert_body 'text/html;charset=utf-8'
get '/', {}, { 'HTTP_ACCEPT' => 'image/png;q=0.8,text/html;q=0.5' }
assert_body 'image/png'
end
it 'accepts generic types' do
mock_app do
get('/', :provides => :xml) { content_type }
get('/') { 'no match' }
end
get '/', {}, { 'HTTP_ACCEPT' => 'foo/*' }
assert_body 'no match'
get '/', {}, { 'HTTP_ACCEPT' => 'application/*' }
assert_body 'application/xml;charset=utf-8'
get '/', {}, { 'HTTP_ACCEPT' => '*/*' }
assert_body 'application/xml;charset=utf-8'
end
it 'prefers concrete over partly generic types' do
mock_app { get('/', :provides => [:png, :html]) { content_type }}
get '/', {}, { 'HTTP_ACCEPT' => 'image/*, text/html' }
assert_body 'text/html;charset=utf-8'
get '/', {}, { 'HTTP_ACCEPT' => 'image/png, text/*' }
assert_body 'image/png'
end
it 'prefers concrete over fully generic types' do
mock_app { get('/', :provides => [:png, :html]) { content_type }}
get '/', {}, { 'HTTP_ACCEPT' => '*/*, text/html' }
assert_body 'text/html;charset=utf-8'
get '/', {}, { 'HTTP_ACCEPT' => 'image/png, */*' }
assert_body 'image/png'
end
it 'prefers partly generic over fully generic types' do
mock_app { get('/', :provides => [:png, :html]) { content_type }}
get '/', {}, { 'HTTP_ACCEPT' => '*/*, text/*' }
assert_body 'text/html;charset=utf-8'
get '/', {}, { 'HTTP_ACCEPT' => 'image/*, */*' }
assert_body 'image/png'
end
it 'respects quality with generic types' do
mock_app { get('/', :provides => [:png, :html]) { content_type }}
get '/', {}, { 'HTTP_ACCEPT' => 'image/*;q=1, text/html;q=0' }
assert_body 'image/png'
get '/', {}, { 'HTTP_ACCEPT' => 'image/png;q=0.5, text/*;q=0.7' }
assert_body 'text/html;charset=utf-8'
end
it 'supplies a default quality of 1.0' do
mock_app { get('/', :provides => [:png, :html]) { content_type }}
get '/', {}, { 'HTTP_ACCEPT' => 'image/png;q=0.5, text/*' }
assert_body 'text/html;charset=utf-8'
end
it 'orders types with equal quality by parameter count' do
mock_app do
get('/', :provides => [:png, :jpg]) { content_type }
end
lo_png = 'image/png;q=0.5'
hi_png = 'image/png;q=0.5;profile=FOGRA40;gamma=0.8'
jpeg = 'image/jpeg;q=0.5;compress=0.25'
get '/', {}, { 'HTTP_ACCEPT' => "#{lo_png}, #{jpeg}" }
assert_body 'image/jpeg'
get '/', {}, { 'HTTP_ACCEPT' => "#{hi_png}, #{jpeg}" }
assert_body 'image/png'
end
it 'ignores the quality parameter when ordering by parameter count' do
mock_app do
get('/', :provides => [:png, :jpg]) { content_type }
end
lo_png = 'image/png'
hi_png = 'image/png;profile=FOGRA40;gamma=0.8'
jpeg = 'image/jpeg;q=1.0;compress=0.25'
get '/', {}, { 'HTTP_ACCEPT' => "#{jpeg}, #{lo_png}" }
assert_body 'image/jpeg'
get '/', {}, { 'HTTP_ACCEPT' => "#{jpeg}, #{hi_png}" }
assert_body 'image/png'
end
it 'properly handles quoted strings in parameters' do
mock_app do
get('/', :provides => [:png, :jpg]) { content_type }
end
get '/', {}, { 'HTTP_ACCEPT' => 'image/png;q=0.5;profile=",image/jpeg,"' }
assert_body 'image/png'
get '/', {}, { 'HTTP_ACCEPT' => 'image/png;q=0.5,image/jpeg;q=0;x=";q=1.0"' }
assert_body 'image/png'
get '/', {}, { 'HTTP_ACCEPT' => 'image/png;q=0.5,image/jpeg;q=0;x="\";q=1.0"' }
assert_body 'image/png'
end
it 'accepts both text/javascript and application/javascript for js' do
mock_app { get('/', :provides => :js) { content_type }}
get '/', {}, { 'HTTP_ACCEPT' => 'application/javascript' }
assert_body 'application/javascript;charset=utf-8'
get '/', {}, { 'HTTP_ACCEPT' => 'text/javascript' }
assert_body 'text/javascript;charset=utf-8'
end
it 'accepts both text/xml and application/xml for xml' do
mock_app { get('/', :provides => :xml) { content_type }}
get '/', {}, { 'HTTP_ACCEPT' => 'application/xml' }
assert_body 'application/xml;charset=utf-8'
get '/', {}, { 'HTTP_ACCEPT' => 'text/xml' }
assert_body 'text/xml;charset=utf-8'
end
it 'passes a single url param as block parameters when one param is specified' do
mock_app {
get '/:foo' do |foo|
assert_equal 'bar', foo
end
}
get '/bar'
assert ok?
end
it 'passes multiple params as block parameters when many are specified' do
mock_app {
get '/:foo/:bar/:baz' do |foo, bar, baz|
assert_equal 'abc', foo
assert_equal 'def', bar
assert_equal 'ghi', baz
end
}
get '/abc/def/ghi'
assert ok?
end
it 'passes regular expression captures as block parameters' do
mock_app {
get(/^\/fo(.*)\/ba(.*)/) do |foo, bar|
assert_equal 'orooomma', foo
assert_equal 'f', bar
'looks good'
end
}
get '/foorooomma/baf'
assert ok?
assert_equal 'looks good', body
end
it "supports mixing multiple splat params like /*/foo/*/* as block parameters" do
mock_app {
get '/*/foo/*/*' do |foo, bar, baz|
assert_equal 'bar', foo
assert_equal 'bling', bar
assert_equal 'baz/boom', baz
'looks good'
end
}
get '/bar/foo/bling/baz/boom'
assert ok?
assert_equal 'looks good', body
end
it 'raises an ArgumentError with block arity > 1 and too many values' do
mock_app do
get '/:foo/:bar/:baz' do |foo, bar|
'quux'
end
end
assert_raise(ArgumentError) { get '/a/b/c' }
end
it 'raises an ArgumentError with block param arity > 1 and too few values' do
mock_app {
get '/:foo/:bar' do |foo, bar, baz|
'quux'
end
}
assert_raise(ArgumentError) { get '/a/b' }
end
it 'succeeds if no block parameters are specified' do
mock_app {
get '/:foo/:bar' do
'quux'
end
}
get '/a/b'
assert ok?
assert_equal 'quux', body
end
it 'passes all params with block param arity -1 (splat args)' do
mock_app {
get '/:foo/:bar' do |*args|
args.join
end
}
get '/a/b'
assert ok?
assert_equal 'ab', body
end
it 'allows custom route-conditions to be set via route options' do
protector = Module.new {
def protect(*args)
condition {
unless authorize(params["user"], params["password"])
halt 403, "go away"
end
}
end
}
mock_app {
register protector
helpers do
def authorize(username, password)
username == "foo" && password == "bar"
end
end
get "/", :protect => true do
"hey"
end
}
get "/"
assert forbidden?
assert_equal "go away", body
get "/", :user => "foo", :password => "bar"
assert ok?
assert_equal "hey", body
end
# NOTE Block params behaves differently under 1.8 and 1.9. Under 1.8, block
# param arity is lax: declaring a mismatched number of block params results
# in a warning. Under 1.9, block param arity is strict: mismatched block
# arity raises an ArgumentError.
if RUBY_VERSION >= '1.9'
it 'raises an ArgumentError with block param arity 1 and no values' do
mock_app {
get '/foo' do |foo|
'quux'
end
}
assert_raise(ArgumentError) { get '/foo' }
end
it 'raises an ArgumentError with block param arity 1 and too many values' do
mock_app {
get '/:foo/:bar/:baz' do |foo|
'quux'
end
}
assert_raise(ArgumentError) { get '/a/b/c' }
end
else
it 'does not raise an ArgumentError with block param arity 1 and no values' do
mock_app {
get '/foo' do |foo|
'quux'
end
}
silence_warnings { get '/foo' }
assert ok?
assert_equal 'quux', body
end
it 'does not raise an ArgumentError with block param arity 1 and too many values' do
mock_app {
get '/:foo/:bar/:baz' do |foo|
'quux'
end
}
silence_warnings { get '/a/b/c' }
assert ok?
assert_equal 'quux', body
end
end
it "matches routes defined in superclasses" do
base = Class.new(Sinatra::Base)
base.get('/foo') { 'foo in baseclass' }
mock_app(base) {
get('/bar') { 'bar in subclass' }
}
get '/foo'
assert ok?
assert_equal 'foo in baseclass', body
get '/bar'
assert ok?
assert_equal 'bar in subclass', body
end
it "matches routes in subclasses before superclasses" do
base = Class.new(Sinatra::Base)
base.get('/foo') { 'foo in baseclass' }
base.get('/bar') { 'bar in baseclass' }
mock_app(base) {
get('/foo') { 'foo in subclass' }
}
get '/foo'
assert ok?
assert_equal 'foo in subclass', body
get '/bar'
assert ok?
assert_equal 'bar in baseclass', body
end
it "adds hostname condition when it is in options" do
mock_app {
get '/foo', :host => 'host' do
'foo'
end
}
get '/foo'
assert not_found?
end
it 'allows using call to fire another request internally' do
mock_app do
get '/foo' do
status, headers, body = call env.merge("PATH_INFO" => '/bar')
[status, headers, body.each.map(&:upcase)]
end
get '/bar' do
"bar"
end
end
get '/foo'
assert ok?
assert_body "BAR"
end
it 'plays well with other routing middleware' do
middleware = Sinatra.new
inner_app = Sinatra.new { get('/foo') { 'hello' } }
builder = Rack::Builder.new do
use middleware
map('/test') { run inner_app }
end
@app = builder.to_app
get '/test/foo'
assert ok?
assert_body 'hello'
end
it 'returns the route signature' do
signature = list = nil
mock_app do
signature = post('/') { }
list = routes['POST']
end
assert_equal Array, signature.class
assert_equal 4, signature.length
assert list.include?(signature)
end
it "sets env['sinatra.route'] to the matched route" do
mock_app do
after do
assert_equal 'GET /users/:id/status', env['sinatra.route']
end
get('/users/:id/status') { 'ok' }
end
get '/users/1/status'
end
end
sinatra-1.4.3/test/result_test.rb 0000644 0000041 0000041 00000003347 12161612727 017105 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
class ResultTest < Test::Unit::TestCase
it "sets response.body when result is a String" do
mock_app { get('/') { 'Hello World' } }
get '/'
assert ok?
assert_equal 'Hello World', body
end
it "sets response.body when result is an Array of Strings" do
mock_app { get('/') { ['Hello', 'World'] } }
get '/'
assert ok?
assert_equal 'HelloWorld', body
end
it "sets response.body when result responds to #each" do
mock_app do
get('/') do
res = lambda { 'Hello World' }
def res.each ; yield call ; end
return res
end
end
get '/'
assert ok?
assert_equal 'Hello World', body
end
it "sets response.body to [] when result is nil" do
mock_app { get( '/') { nil } }
get '/'
assert ok?
assert_equal '', body
end
it "sets status, headers, and body when result is a Rack response tuple" do
mock_app {
get('/') { [203, {'Content-Type' => 'foo/bar'}, 'Hello World'] }
}
get '/'
assert_equal 203, status
assert_equal 'foo/bar', response['Content-Type']
assert_equal 'Hello World', body
end
it "sets status and body when result is a two-tuple" do
mock_app { get('/') { [409, 'formula of'] } }
get '/'
assert_equal 409, status
assert_equal 'formula of', body
end
it "raises a ArgumentError when result is a non two or three tuple Array" do
mock_app {
get('/') { [409, 'formula of', 'something else', 'even more'] }
}
assert_raise(ArgumentError) { get '/' }
end
it "sets status when result is a Fixnum status code" do
mock_app { get('/') { 205 } }
get '/'
assert_equal 205, status
assert_equal '', body
end
end
sinatra-1.4.3/test/slim_test.rb 0000644 0000041 0000041 00000005170 12161612727 016527 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
begin
require 'slim'
class SlimTest < Test::Unit::TestCase
def slim_app(&block)
mock_app do
set :views, File.dirname(__FILE__) + '/views'
get('/', &block)
end
get '/'
end
it 'renders inline slim strings' do
slim_app { slim "h1 Hiya\n" }
assert ok?
assert_equal "Hiya
", body
end
it 'renders .slim files in views path' do
slim_app { slim :hello }
assert ok?
assert_equal "Hello From Slim
", body
end
it "renders with inline layouts" do
mock_app do
layout { %(h1\n | THIS. IS. \n == yield.upcase ) }
get('/') { slim 'em Sparta' }
end
get '/'
assert ok?
assert_equal "THIS. IS. SPARTA
", body
end
it "renders with file layouts" do
slim_app { slim('| Hello World', :layout => :layout2) }
assert ok?
assert_equal "Slim Layout!
Hello World
", body
end
it "raises error if template not found" do
mock_app { get('/') { slim(:no_such_template) } }
assert_raise(Errno::ENOENT) { get('/') }
end
HTML4_DOCTYPE = ""
it "passes slim options to the slim engine" do
mock_app { get('/') { slim("x foo='bar'", :attr_wrapper => "'") }}
get '/'
assert ok?
assert_body ""
end
it "passes default slim options to the slim engine" do
mock_app do
set :slim, :attr_wrapper => "'"
get('/') { slim("x foo='bar'") }
end
get '/'
assert ok?
assert_body ""
end
it "merges the default slim options with the overrides and passes them to the slim engine" do
mock_app do
set :slim, :attr_wrapper => "'"
get('/') { slim("x foo='bar'") }
get('/other') { slim("x foo='bar'", :attr_wrapper => '"') }
end
get '/'
assert ok?
assert_body ""
get '/other'
assert ok?
assert_body ''
end
it "can render truly nested layouts by accepting a layout and a block with the contents" do
mock_app do
template(:main_outer_layout) { "h1 Title\n== yield" }
template(:an_inner_layout) { "h2 Subtitle\n== yield" }
template(:a_page) { "p Contents." }
get('/') do
slim :main_outer_layout, :layout => false do
slim :an_inner_layout do
slim :a_page
end
end
end
end
get '/'
assert ok?
assert_body "Title
\nSubtitle
\nContents.
\n"
end
end
rescue LoadError
warn "#{$!.to_s}: skipping slim tests"
end
sinatra-1.4.3/test/rabl_test.rb 0000644 0000041 0000041 00000003714 12161612727 016505 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
begin
require 'rabl'
require 'ostruct'
require 'json'
require 'active_support/core_ext/hash/conversions'
class RablTest < Test::Unit::TestCase
def rabl_app(&block)
mock_app {
set :views, File.dirname(__FILE__) + '/views'
get '/', &block
}
get '/'
end
it 'renders inline rabl strings' do
rabl_app do
@foo = OpenStruct.new(:baz => 'w00t')
rabl %q{
object @foo
attributes :baz
}
end
assert ok?
assert_equal '{"openstruct":{"baz":"w00t"}}', body
end
it 'renders .rabl files in views path' do
rabl_app do
@foo = OpenStruct.new(:bar => 'baz')
rabl :hello
end
assert ok?
assert_equal '{"openstruct":{"bar":"baz"}}', body
end
it "renders with file layouts" do
rabl_app {
@foo = OpenStruct.new(:bar => 'baz')
rabl :hello, :layout => :layout2
}
assert ok?
assert_equal '{"qux":{"openstruct":{"bar":"baz"}}}', body
end
it "raises error if template not found" do
mock_app {
get('/') { rabl :no_such_template }
}
assert_raise(Errno::ENOENT) { get('/') }
end
it "passes rabl options to the rabl engine" do
mock_app do
get('/') do
@foo = OpenStruct.new(:bar => 'baz')
rabl %q{
object @foo
attributes :bar
}, :format => 'xml'
end
end
get '/'
assert ok?
assert_body 'baz'
end
it "passes default rabl options to the rabl engine" do
mock_app do
set :rabl, :format => 'xml'
get('/') do
@foo = OpenStruct.new(:bar => 'baz')
rabl %q{
object @foo
attributes :bar
}
end
end
get '/'
assert ok?
assert_body 'baz'
end
end
rescue LoadError
warn "#{$!.to_s}: skipping rabl tests"
end
sinatra-1.4.3/test/rack_test.rb 0000644 0000041 0000041 00000002047 12161612727 016503 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
require 'rack'
class RackTest < Test::Unit::TestCase
setup do
@foo = Sinatra.new { get('/foo') { 'foo' }}
@bar = Sinatra.new { get('/bar') { 'bar' }}
end
def build(*middleware)
endpoint = middleware.pop
@app = Rack::Builder.app do
middleware.each { |m| use m }
run endpoint
end
end
def check(*middleware)
build(*middleware)
assert get('/foo').ok?
assert_body 'foo'
assert get('/bar').ok?
assert_body 'bar'
end
it 'works as middleware in front of Rack::Lock, with lock enabled' do
@foo.enable :lock
check(@foo, Rack::Lock, @bar)
end
it 'works as middleware behind Rack::Lock, with lock enabled' do
@foo.enable :lock
check(Rack::Lock, @foo, @bar)
end
it 'works as middleware in front of Rack::Lock, with lock disabled' do
@foo.disable :lock
check(@foo, Rack::Lock, @bar)
end
it 'works as middleware behind Rack::Lock, with lock disabled' do
@foo.disable :lock
check(Rack::Lock, @foo, @bar)
end
end
sinatra-1.4.3/test/stylus_test.rb 0000644 0000041 0000041 00000004414 12161612727 017126 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
begin
require 'stylus'
require 'stylus/tilt'
begin
Stylus.compile '1'
rescue RuntimeError
raise LoadError, 'unable to find Stylus compiler'
end
class StylusTest < Test::Unit::TestCase
def stylus_app(options = {}, &block)
mock_app do
set :views, File.dirname(__FILE__) + '/views'
set(options)
get('/', &block)
end
get '/'
end
it 'renders inline Stylus strings' do
stylus_app { stylus "a\n margin auto\n" }
assert ok?
assert body.include?("a {\n margin: auto;\n}\n")
end
it 'defaults content type to css' do
stylus_app { stylus :hello }
assert ok?
assert_equal "text/css;charset=utf-8", response['Content-Type']
end
it 'defaults allows setting content type per route' do
stylus_app do
content_type :html
stylus :hello
end
assert ok?
assert_equal "text/html;charset=utf-8", response['Content-Type']
end
it 'defaults allows setting content type globally' do
stylus_app(:styl => { :content_type => 'html' }) do
stylus :hello
end
assert ok?
assert_equal "text/html;charset=utf-8", response['Content-Type']
end
it 'renders .styl files in views path' do
stylus_app { stylus :hello }
assert ok?
assert_include body, "a {\n margin: auto;\n}\n"
end
it 'ignores the layout option' do
stylus_app { stylus :hello, :layout => :layout2 }
assert ok?
assert_include body, "a {\n margin: auto;\n}\n"
end
it "raises error if template not found" do
mock_app {
get('/') { stylus :no_such_template }
}
assert_raise(Errno::ENOENT) { get('/') }
end
it "passes stylus options to the stylus engine" do
stylus_app { stylus :hello, :no_wrap => true }
assert ok?
assert_body "a {\n margin: auto;\n}\n"
end
it "passes default stylus options to the stylus engine" do
mock_app do
set :stylus, :no_wrap => true # default stylus style is :nested
get('/') { stylus :hello }
end
get '/'
assert ok?
assert_body "a {\n margin: auto;\n}\n"
end
end
rescue LoadError
warn "#{$!.to_s}: skipping stylus tests"
end
sinatra-1.4.3/test/streaming_test.rb 0000644 0000041 0000041 00000007026 12161612727 017556 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
class StreamingTest < Test::Unit::TestCase
Stream = Sinatra::Helpers::Stream
it 'returns the concatenated body' do
mock_app do
get('/') do
stream do |out|
out << "Hello" << " "
out << "World!"
end
end
end
get('/')
assert_body "Hello World!"
end
it 'always yields strings' do
stream = Stream.new { |out| out << :foo }
stream.each { |str| assert_equal 'foo', str }
end
it 'postpones body generation' do
step = 0
stream = Stream.new do |out|
10.times do
out << step
step += 1
end
end
stream.each do |s|
assert_equal s, step.to_s
step += 1
end
end
it 'calls the callback after it is done' do
step = 0
final = 0
stream = Stream.new { |_| 10.times { step += 1 }}
stream.callback { final = step }
stream.each {|_|}
assert_equal 10, final
end
it 'does not trigger the callback if close is set to :keep_open' do
step = 0
final = 0
stream = Stream.new(Stream, :keep_open) { |_| 10.times { step += 1 } }
stream.callback { final = step }
stream.each {|_|}
assert_equal 0, final
end
it 'allows adding more than one callback' do
a = b = false
stream = Stream.new { }
stream.callback { a = true }
stream.callback { b = true }
stream.each {|_| }
assert a, 'should trigger first callback'
assert b, 'should trigger second callback'
end
class MockScheduler
def initialize(*) @schedule, @defer = [], [] end
def schedule(&block) @schedule << block end
def defer(&block) @defer << block end
def schedule!(*) @schedule.pop.call until @schedule.empty? end
def defer!(*) @defer.pop.call until @defer.empty? end
end
it 'allows dropping in another scheduler' do
scheduler = MockScheduler.new
processing = sending = done = false
stream = Stream.new(scheduler) do |out|
processing = true
out << :foo
end
stream.each { sending = true}
stream.callback { done = true }
scheduler.schedule!
assert !processing
assert !sending
assert !done
scheduler.defer!
assert processing
assert !sending
assert !done
scheduler.schedule!
assert sending
assert done
end
it 'schedules exceptions to be raised on the main thread/event loop/...' do
scheduler = MockScheduler.new
Stream.new(scheduler) { fail 'should be caught' }.each { }
scheduler.defer!
assert_raise(RuntimeError) { scheduler.schedule! }
end
it 'does not trigger an infinite loop if you call close in a callback' do
stream = Stream.new { |out| out.callback { out.close }}
stream.each { |_| }
end
it 'gives access to route specific params' do
mock_app do
get('/:name') do
stream { |o| o << params[:name] }
end
end
get '/foo'
assert_body 'foo'
end
it 'sets up async.close if available' do
ran = false
mock_app do
get('/') do
close = Object.new
def close.callback; yield end
def close.errback; end
env['async.close'] = close
stream(:keep_open) do |out|
out.callback { ran = true }
end
end
end
get '/'
assert ran
end
it 'has a public interface to inspect its open/closed state' do
stream = Stream.new(Stream) { |out| out << :foo }
assert !stream.closed?
stream.close
assert stream.closed?
end
end
sinatra-1.4.3/test/integration/ 0000755 0000041 0000041 00000000000 12161612727 016517 5 ustar www-data www-data sinatra-1.4.3/test/integration/app.rb 0000644 0000041 0000041 00000001641 12161612727 017626 0 ustar www-data www-data $stderr.puts "loading"
require 'sinatra'
configure do
set :foo, :bar
end
get '/app_file' do
content_type :txt
settings.app_file
end
get '/ping' do
'pong'
end
get '/stream' do
stream do |out|
sleep 0.1
out << "a"
sleep 1.2
out << "b"
end
end
get '/mainonly' do
object = Object.new
begin
object.send(:get, '/foo') { }
'false'
rescue NameError
'true'
end
end
set :out, nil
get '/async' do
stream(:keep_open) { |o| (settings.out = o) << "hi!" }
end
get '/send' do
settings.out << params[:msg] if params[:msg]
settings.out.close if params[:close]
"ok"
end
class Subclass < Sinatra::Base
set :out, nil
get '/subclass/async' do
stream(:keep_open) { |o| (settings.out = o) << "hi!" }
end
get '/subclass/send' do
settings.out << params[:msg] if params[:msg]
settings.out.close if params[:close]
"ok"
end
end
use Subclass
$stderr.puts "starting"
sinatra-1.4.3/test/compile_test.rb 0000644 0000041 0000041 00000020120 12161612727 017203 0 ustar www-data www-data # I like coding: UTF-8
require File.expand_path('../helper', __FILE__)
class CompileTest < Test::Unit::TestCase
def self.converts pattern, expected_regexp
it "generates #{expected_regexp.source} from #{pattern}" do
compiled, _ = compiled pattern
assert_equal expected_regexp, compiled, "Pattern #{pattern} is not compiled into #{expected_regexp.source}. Was #{compiled.source}."
end
end
def self.parses pattern, example, expected_params
it "parses #{example} with #{pattern} into params #{expected_params}" do
compiled, keys = compiled pattern
match = compiled.match(example)
fail %Q{"#{example}" does not parse on pattern "#{pattern}" (compiled pattern is #{compiled.source}).} unless match
# Aggregate e.g. multiple splat values into one array.
#
params = keys.zip(match.captures).reduce({}) do |hash, mapping|
key, value = mapping
hash[key] = if existing = hash[key]
existing.respond_to?(:to_ary) ? existing << value : [existing, value]
else
value
end
hash
end
assert_equal expected_params, params, "Pattern #{pattern} does not match path #{example}."
end
end
def self.fails pattern, example
it "does not parse #{example} with #{pattern}" do
compiled, _ = compiled pattern
match = compiled.match(example)
fail %Q{"#{pattern}" does parse "#{example}" but it should fail} if match
end
end
def compiled pattern
app ||= mock_app {}
compiled, keys = app.send(:compile, pattern)
[compiled, keys]
end
converts "/", %r{\A/\z}
parses "/", "/", {}
converts "/foo", %r{\A/foo\z}
parses "/foo", "/foo", {}
converts "/:foo", %r{\A/([^/?#]+)\z}
parses "/:foo", "/foo", "foo" => "foo"
parses "/:foo", "/foo.bar", "foo" => "foo.bar"
parses "/:foo", "/foo%2Fbar", "foo" => "foo%2Fbar"
parses "/:foo", "/%0Afoo", "foo" => "%0Afoo"
fails "/:foo", "/foo?"
fails "/:foo", "/foo/bar"
fails "/:foo", "/"
fails "/:foo", "/foo/"
converts "/föö", %r{\A/f%[Cc]3%[Bb]6%[Cc]3%[Bb]6\z}
parses "/föö", "/f%C3%B6%C3%B6", {}
converts "/:foo/:bar", %r{\A/([^/?#]+)/([^/?#]+)\z}
parses "/:foo/:bar", "/foo/bar", "foo" => "foo", "bar" => "bar"
converts "/hello/:person", %r{\A/hello/([^/?#]+)\z}
parses "/hello/:person", "/hello/Frank", "person" => "Frank"
converts "/?:foo?/?:bar?", %r{\A/?([^/?#]+)?/?([^/?#]+)?\z}
parses "/?:foo?/?:bar?", "/hello/world", "foo" => "hello", "bar" => "world"
parses "/?:foo?/?:bar?", "/hello", "foo" => "hello", "bar" => nil
parses "/?:foo?/?:bar?", "/", "foo" => nil, "bar" => nil
parses "/?:foo?/?:bar?", "", "foo" => nil, "bar" => nil
converts "/*", %r{\A/(.*?)\z}
parses "/*", "/", "splat" => ""
parses "/*", "/foo", "splat" => "foo"
parses "/*", "/foo/bar", "splat" => "foo/bar"
converts "/:foo/*", %r{\A/([^/?#]+)/(.*?)\z}
parses "/:foo/*", "/foo/bar/baz", "foo" => "foo", "splat" => "bar/baz"
converts "/:foo/:bar", %r{\A/([^/?#]+)/([^/?#]+)\z}
parses "/:foo/:bar", "/user@example.com/name", "foo" => "user@example.com", "bar" => "name"
converts "/test$/", %r{\A/test(?:\$|%24)/\z}
parses "/test$/", "/test$/", {}
converts "/te+st/", %r{\A/te(?:\+|%2[Bb])st/\z}
parses "/te+st/", "/te+st/", {}
fails "/te+st/", "/test/"
fails "/te+st/", "/teeest/"
converts "/test(bar)/", %r{\A/test(?:\(|%28)bar(?:\)|%29)/\z}
parses "/test(bar)/", "/test(bar)/", {}
converts "/path with spaces", %r{\A/path(?:%20|(?:\+|%2[Bb]))with(?:%20|(?:\+|%2[Bb]))spaces\z}
parses "/path with spaces", "/path%20with%20spaces", {}
parses "/path with spaces", "/path%2Bwith%2Bspaces", {}
parses "/path with spaces", "/path+with+spaces", {}
converts "/foo&bar", %r{\A/foo(?:&|%26)bar\z}
parses "/foo&bar", "/foo&bar", {}
converts "/:foo/*", %r{\A/([^/?#]+)/(.*?)\z}
parses "/:foo/*", "/hello%20world/how%20are%20you", "foo" => "hello%20world", "splat" => "how%20are%20you"
converts "/*/foo/*/*", %r{\A/(.*?)/foo/(.*?)/(.*?)\z}
parses "/*/foo/*/*", "/bar/foo/bling/baz/boom", "splat" => ["bar", "bling", "baz/boom"]
fails "/*/foo/*/*", "/bar/foo/baz"
converts "/test.bar", %r{\A/test(?:\.|%2[Ee])bar\z}
parses "/test.bar", "/test.bar", {}
fails "/test.bar", "/test0bar"
converts "/:file.:ext", %r{\A/((?:[^\./?#%]|(?:%[^2].|%[2][^Ee]))+)(?:\.|%2[Ee])((?:[^/?#%]|(?:%[^2].|%[2][^Ee]))+)\z}
parses "/:file.:ext", "/pony.jpg", "file" => "pony", "ext" => "jpg"
parses "/:file.:ext", "/pony%2Ejpg", "file" => "pony", "ext" => "jpg"
fails "/:file.:ext", "/.jpg"
converts "/:name.?:format?", %r{\A/((?:[^\./?#%]|(?:%[^2].|%[2][^Ee]))+)(?:\.|%2[Ee])?((?:[^/?#%]|(?:%[^2].|%[2][^Ee]))+)?\z}
parses "/:name.?:format?", "/foo", "name" => "foo", "format" => nil
parses "/:name.?:format?", "/foo.bar", "name" => "foo", "format" => "bar"
parses "/:name.?:format?", "/foo%2Ebar", "name" => "foo", "format" => "bar"
parses "/:name?.?:format", "/.bar", "name" => nil, "format" => "bar"
parses "/:name?.?:format?", "/.bar", "name" => nil, "format" => "bar"
parses "/:name?.:format?", "/.bar", "name" => nil, "format" => "bar"
fails "/:name.:format", "/.bar"
fails "/:name.?:format?", "/.bar"
converts "/:user@?:host?", %r{\A/((?:[^@/?#%]|(?:%[^4].|%[4][^0]))+)(?:@|%40)?((?:[^@/?#%]|(?:%[^4].|%[4][^0]))+)?\z}
parses "/:user@?:host?", "/foo@bar", "user" => "foo", "host" => "bar"
parses "/:user@?:host?", "/foo.foo@bar", "user" => "foo.foo", "host" => "bar"
parses "/:user@?:host?", "/foo@bar.bar", "user" => "foo", "host" => "bar.bar"
# From https://gist.github.com/2154980#gistcomment-169469.
#
# converts "/:name(.:format)?", %r{\A/([^\.%2E/?#]+)(?:\(|%28)(?:\.|%2E)([^\.%2E/?#]+)(?:\)|%29)?\z}
# parses "/:name(.:format)?", "/foo", "name" => "foo", "format" => nil
# parses "/:name(.:format)?", "/foo.bar", "name" => "foo", "format" => "bar"
fails "/:name(.:format)?", "/foo."
parses "/:id/test.bar", "/3/test.bar", {"id" => "3"}
parses "/:id/test.bar", "/2/test.bar", {"id" => "2"}
parses "/:id/test.bar", "/2E/test.bar", {"id" => "2E"}
parses "/:id/test.bar", "/2e/test.bar", {"id" => "2e"}
parses "/:id/test.bar", "/%2E/test.bar", {"id" => "%2E"}
parses '/10/:id', '/10/test', "id" => "test"
parses '/10/:id', '/10/te.st', "id" => "te.st"
parses '/10.1/:id', '/10.1/test', "id" => "test"
parses '/10.1/:id', '/10.1/te.st', "id" => "te.st"
parses '/:foo/:id', '/10.1/te.st', "foo" => "10.1", "id" => "te.st"
parses '/:foo/:id', '/10.1.2/te.st', "foo" => "10.1.2", "id" => "te.st"
parses '/:foo.:bar/:id', '/10.1/te.st', "foo" => "10", "bar" => "1", "id" => "te.st"
fails '/:foo.:bar/:id', '/10.1.2/te.st' # We don't do crazy.
parses '/:a/:b.?:c?', '/a/b', "a" => "a", "b" => "b", "c" => nil
parses '/:a/:b.?:c?', '/a/b.c', "a" => "a", "b" => "b", "c" => "c"
parses '/:a/:b.?:c?', '/a.b/c', "a" => "a.b", "b" => "c", "c" => nil
parses '/:a/:b.?:c?', '/a.b/c.d', "a" => "a.b", "b" => "c", "c" => "d"
fails '/:a/:b.?:c?', '/a.b/c.d/e'
parses "/:file.:ext", "/pony%2ejpg", "file" => "pony", "ext" => "jpg"
parses "/:file.:ext", "/pony%E6%AD%A3%2Ejpg", "file" => "pony%E6%AD%A3", "ext" => "jpg"
parses "/:file.:ext", "/pony%e6%ad%a3%2ejpg", "file" => "pony%e6%ad%a3", "ext" => "jpg"
parses "/:file.:ext", "/pony正%2Ejpg", "file" => "pony正", "ext" => "jpg"
parses "/:file.:ext", "/pony正%2ejpg", "file" => "pony正", "ext" => "jpg"
parses "/:file.:ext", "/pony正..jpg", "file" => "pony正", "ext" => ".jpg"
fails "/:file.:ext", "/pony正.%2ejpg"
converts "/:name.:format", %r{\A/((?:[^\./?#%]|(?:%[^2].|%[2][^Ee]))+)(?:\.|%2[Ee])((?:[^/?#%]|(?:%[^2].|%[2][^Ee]))+)\z}
parses "/:name.:format", "/file.tar.gz", "name" => "file", "format" => "tar.gz"
parses "/:name.:format1.:format2", "/file.tar.gz", "name" => "file", "format1" => "tar", "format2" => "gz"
parses "/:name.:format1.:format2", "/file.temp.tar.gz", "name" => "file", "format1" => "temp", "format2" => "tar.gz"
# From issue #688.
#
parses "/articles/10.1103/:doi", "/articles/10.1103/PhysRevLett.110.026401", "doi" => "PhysRevLett.110.026401"
end
sinatra-1.4.3/test/builder_test.rb 0000644 0000041 0000041 00000004312 12161612727 017206 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
begin
require 'builder'
class BuilderTest < Test::Unit::TestCase
def builder_app(options = {}, &block)
mock_app do
set :views, File.dirname(__FILE__) + '/views'
set options
get('/', &block)
end
get '/'
end
it 'renders inline Builder strings' do
builder_app { builder 'xml.instruct!' }
assert ok?
assert_equal %{\n}, body
end
it 'defaults content type to xml' do
builder_app { builder 'xml.instruct!' }
assert ok?
assert_equal "application/xml;charset=utf-8", response['Content-Type']
end
it 'defaults allows setting content type per route' do
builder_app do
content_type :html
builder 'xml.instruct!'
end
assert ok?
assert_equal "text/html;charset=utf-8", response['Content-Type']
end
it 'defaults allows setting content type globally' do
builder_app(:builder => { :content_type => 'html' }) do
builder 'xml.instruct!'
end
assert ok?
assert_equal "text/html;charset=utf-8", response['Content-Type']
end
it 'renders inline blocks' do
builder_app do
@name = "Frank & Mary"
builder { |xml| xml.couple @name }
end
assert ok?
assert_equal "Frank & Mary\n", body
end
it 'renders .builder files in views path' do
builder_app do
@name = "Blue"
builder :hello
end
assert ok?
assert_equal %(You're my boy, Blue!\n), body
end
it "renders with inline layouts" do
mock_app do
layout { %(xml.layout { xml << yield }) }
get('/') { builder %(xml.em 'Hello World') }
end
get '/'
assert ok?
assert_equal "\nHello World\n\n", body
end
it "renders with file layouts" do
builder_app do
builder %(xml.em 'Hello World'), :layout => :layout2
end
assert ok?
assert_equal "\nHello World\n\n", body
end
it "raises error if template not found" do
mock_app do
get('/') { builder :no_such_template }
end
assert_raise(Errno::ENOENT) { get('/') }
end
end
rescue LoadError
warn "#{$!.to_s}: skipping builder tests"
end
sinatra-1.4.3/test/views/ 0000755 0000041 0000041 00000000000 12161612727 015331 5 ustar www-data www-data sinatra-1.4.3/test/views/hello.str 0000644 0000041 0000041 00000000032 12161612727 017161 0 ustar www-data www-data Hello From String