Browse Source

Merge branch 'staging'

Taylor Otwell 12 years ago
parent
commit
1e20052b08
100 changed files with 6985 additions and 184 deletions
  1. 10 0
      .travis.yml
  2. 5 0
      application/language/ar/validation.php
  3. 5 0
      application/language/bg/validation.php
  4. 5 0
      application/language/de/validation.php
  5. 5 0
      application/language/en/validation.php
  6. 5 0
      application/language/fr/validation.php
  7. 5 0
      application/language/he/validation.php
  8. 5 0
      application/language/hu/validation.php
  9. 5 0
      application/language/id/validation.php
  10. 5 0
      application/language/ja/validation.php
  11. 5 0
      application/language/nl/validation.php
  12. 93 88
      application/language/pl/validation.php
  13. 5 0
      application/language/ru/validation.php
  14. 28 0
      application/language/tr/pagination.php
  15. 108 0
      application/language/tr/validation.php
  16. 12 0
      laravel/bundle.php
  17. 0 24
      laravel/cli/tasks/test/phpunit.php
  18. 23 20
      laravel/cli/tasks/test/runner.php
  19. 14 0
      laravel/core.php
  20. 15 16
      laravel/database/eloquent/query.php
  21. 32 16
      laravel/database/query.php
  22. 1 1
      laravel/database/schema/grammars/mysql.php
  23. 11 0
      laravel/documentation/changes.md
  24. 19 19
      laravel/profiling/profiler.js
  25. 19 0
      laravel/redirect.php
  26. 2 0
      laravel/routing/controller.php
  27. 36 0
      laravel/tests/application/bundles.php
  28. 158 0
      laravel/tests/application/config/application.php
  29. 73 0
      laravel/tests/application/config/auth.php
  30. 71 0
      laravel/tests/application/config/cache.php
  31. 108 0
      laravel/tests/application/config/database.php
  32. 69 0
      laravel/tests/application/config/error.php
  33. 7 0
      laravel/tests/application/config/local/database.php
  34. 97 0
      laravel/tests/application/config/mimes.php
  35. 117 0
      laravel/tests/application/config/session.php
  36. 187 0
      laravel/tests/application/config/strings.php
  37. 10 0
      laravel/tests/application/controllers/admin/panel.php
  38. 20 0
      laravel/tests/application/controllers/auth.php
  39. 65 0
      laravel/tests/application/controllers/filter.php
  40. 42 0
      laravel/tests/application/controllers/home.php
  41. 17 0
      laravel/tests/application/controllers/restful.php
  42. 12 0
      laravel/tests/application/controllers/template/basic.php
  43. 12 0
      laravel/tests/application/controllers/template/named.php
  44. 26 0
      laravel/tests/application/controllers/template/override.php
  45. 7 0
      laravel/tests/application/dashboard/repository.php
  46. 19 0
      laravel/tests/application/language/en/pagination.php
  47. 96 0
      laravel/tests/application/language/en/validation.php
  48. 7 0
      laravel/tests/application/language/sp/validation.php
  49. 0 0
      laravel/tests/application/libraries/.gitignore
  50. 0 0
      laravel/tests/application/migrations/.gitignore
  51. 0 0
      laravel/tests/application/models/.gitignore
  52. 3 0
      laravel/tests/application/models/autoloader.php
  53. 3 0
      laravel/tests/application/models/repositories/user.php
  54. 3 0
      laravel/tests/application/models/user.php
  55. 93 0
      laravel/tests/application/routes.php
  56. 157 0
      laravel/tests/application/start.php
  57. 0 0
      laravel/tests/application/tasks/.gitignore
  58. 103 0
      laravel/tests/application/views/error/404.php
  59. 103 0
      laravel/tests/application/views/error/500.php
  60. 122 0
      laravel/tests/application/views/home/index.php
  61. 1 0
      laravel/tests/application/views/tests/basic.php
  62. 1 0
      laravel/tests/application/views/tests/nested.php
  63. 0 0
      laravel/tests/bundles/.gitignore
  64. 7 0
      laravel/tests/bundles/dashboard/config/meta.php
  65. 10 0
      laravel/tests/bundles/dashboard/controllers/panel.php
  66. 7 0
      laravel/tests/bundles/dashboard/models/repository.php
  67. 8 0
      laravel/tests/bundles/dashboard/routes.php
  68. 6 0
      laravel/tests/bundles/dummy/routes.php
  69. 3 0
      laravel/tests/bundles/dummy/start.php
  70. 258 0
      laravel/tests/cases/asset.test.php
  71. 359 0
      laravel/tests/cases/auth.test.php
  72. 102 0
      laravel/tests/cases/autoloader.test.php
  73. 63 0
      laravel/tests/cases/blade.test.php
  74. 251 0
      laravel/tests/cases/bundle.test.php
  75. 79 0
      laravel/tests/cases/config.test.php
  76. 267 0
      laravel/tests/cases/controller.test.php
  77. 134 0
      laravel/tests/cases/cookie.test.php
  78. 74 0
      laravel/tests/cases/database.test.php
  79. 43 0
      laravel/tests/cases/event.test.php
  80. 50 0
      laravel/tests/cases/fluent.test.php
  81. 37 0
      laravel/tests/cases/hash.test.php
  82. 174 0
      laravel/tests/cases/input.test.php
  83. 74 0
      laravel/tests/cases/ioc.test.php
  84. 68 0
      laravel/tests/cases/lang.test.php
  85. 115 0
      laravel/tests/cases/messages.test.php
  86. 48 0
      laravel/tests/cases/query.test.php
  87. 143 0
      laravel/tests/cases/redirect.test.php
  88. 177 0
      laravel/tests/cases/request.test.php
  89. 89 0
      laravel/tests/cases/response.test.php
  90. 179 0
      laravel/tests/cases/route.test.php
  91. 160 0
      laravel/tests/cases/routing.test.php
  92. 443 0
      laravel/tests/cases/session.test.php
  93. 133 0
      laravel/tests/cases/str.test.php
  94. 75 0
      laravel/tests/cases/uri.test.php
  95. 106 0
      laravel/tests/cases/url.test.php
  96. 669 0
      laravel/tests/cases/validator.test.php
  97. 255 0
      laravel/tests/cases/view.test.php
  98. 32 0
      laravel/tests/phpunit.php
  99. 0 0
      laravel/tests/storage/cache/.gitignore
  100. BIN
      laravel/tests/storage/database/application.sqlite

+ 10 - 0
.travis.yml

@@ -0,0 +1,10 @@
+language: php
+
+php:
+  - 5.3
+
+script: "php artisan test:core"
+
+notifications:
+  irc:
+    - "irc.freenode.org#laravel"

+ 5 - 0
application/language/ar/validation.php

@@ -24,6 +24,7 @@ return array(
 	"alpha"          => "ุงู„ู‚ูŠู…ุฉ :attribute ูŠู…ูƒู†ู‡ุง ุฃู† ุชุญุชูˆูŠ ุนู„ู‰ ุฃุญุฑู ูู‚ุท.",
 	"alpha_dash"     => "ุงู„ู‚ูŠู…ุฉ :attribute ูŠู…ูƒู†ู‡ุง ุฃู† ุชุญุชูˆูŠ ุนู„ู‰ ุฃุญุฑู ูˆ ุฃุฑู‚ุงู… ูˆ ุฅุดุงุฑุฉ ุงู„ู†ุงู‚ุต ูู‚ุท.",
 	"alpha_num"      => "ุงู„ู‚ูŠู…ุฉ :attribute ูŠู…ูƒู†ู‡ุง ุฃู† ุชุญุชูˆูŠ ุนู„ู‰ ุฃุญุฑู ูˆ ุฃุฑู‚ุงู… ูู‚ุท.",
+	"array"          => "The :attribute must have selected elements.",
 	"before"         => "ุงู„ู‚ูŠู…ุฉ :attribute ูŠุฌุจ ุฃู† ุชูƒูˆู† ู‚ุจู„ ุชุงุฑูŠุฎ :date.",
 	"between"        => array(
 		"numeric" => "ุงู„ู‚ูŠู…ุฉ :attribute ูŠุฌุจ ุฃู† ุชูƒูˆู† ุจูŠู† :min ูˆ :max.",
@@ -31,6 +32,10 @@ return array(
 		"string"  => "ุงู„ู†ุต :attribute ูŠุฌุจ ุฃู† ูŠูƒูˆู† ุจุทูˆู„ ู…ู† :min ุฅู„ู‰ :max ุญุฑู.",
 	),
 	"confirmed"      => "ุงู„ู‚ูŠู…ุฉ :attribute ุงู„ุชุฃูƒูŠุฏูŠุฉ ุบูŠุฑ ู…ุทุงุจู‚ุฉ.",
+	"count"          => "The :attribute must have exactly :count selected elements.",
+	"countbetween"   => "The :attribute must have between :min and :max selected elements.",
+	"countmax"       => "The :attribute must have less than :max selected elements.",
+	"countmin"       => "The :attribute must have at least :min selected elements.",
 	"different"      => "ุงู„ู‚ูŠู…ุชุงู† :attribute ูˆ :other ูŠุฌุจ ุฃู† ุชุฎุชู„ูุงู†.",
 	"email"          => "ุงู„ู‚ูŠู…ุฉ :attribute ุชู…ุซู„ ุจุฑูŠุฏ ุฅู„ูƒุชุฑูˆู†ูŠ ุบูŠุฑ ุตุญูŠุญ.",
 	"exists"         => "ุงู„ู‚ูŠู…ุฉ ุงู„ู…ุฎุชุงุฑุฉ :attribute ุบูŠุฑ ู…ูˆุฌูˆุฏุฉ.",

+ 5 - 0
application/language/bg/validation.php

@@ -24,6 +24,7 @@ return array(
 	"alpha"          => "ะŸะพะปะตั‚ะพ :attribute ั‚ั€ัะฑะฒะฐ ะดะฐ ััŠะดัŠั€ะถะฐ ัะฐะผะพ ะฑัƒะบะฒะธ.",
 	"alpha_dash"     => "ะŸะพะปะตั‚ะพ :attribute ั‚ั€ัะฑะฒะฐ ะดะฐ ััŠะดัŠั€ะถะฐ ัะฐะผะพ ะฑัƒะบะฒะธ, ั†ะธั„ั€ะธ, ะดะพะปะฝะฐ ั‡ะตั€ั‚ะฐ ะธ ั‚ะธั€ะต.",
 	"alpha_num"      => "ะŸะพะปะตั‚ะพ :attribute ั‚ั€ัะฑะฒะฐ ะดะฐ ััŠะดัŠั€ะถะฐ ัะฐะผะพ ะฑัƒะบะฒะธ ะธ ั†ะธั„ั€ะธ.",
+	"array"          => "The :attribute must have selected elements.",
 	"before"         => "ะŸะพะปะตั‚ะพ :attribute ั‚ั€ัะฑะฒะฐ ะดะฐ ะฑัŠะดะต ะดะฐั‚ะฐ ะฟั€ะตะดะธ :date.",
 	"between"        => array(
 		"numeric" => "ะŸะพะปะตั‚ะพ :attribute ั‚ั€ัะฑะฒะฐ ะดะฐ ะฑัŠะดะต ะผะตะถะดัƒ :min ะธ :max.",
@@ -31,6 +32,10 @@ return array(
 		"string"  => "ะŸะพะปะตั‚ะพ :attribute ั‚ั€ัะฑะฒะฐ ะดะฐ ะฑัŠะดะต ะผะตะถะดัƒ :min ะธ :max ะทะฝะฐะบะฐ.",
 	),
 	"confirmed"      => "ะŸะพะปะตั‚ะพ :attribute ะฝะต ะต ะฟะพั‚ะฒัŠั€ะดะตะฝะพ.",
+	"count"          => "The :attribute must have exactly :count selected elements.",
+	"countbetween"   => "The :attribute must have between :min and :max selected elements.",
+	"countmax"       => "The :attribute must have less than :max selected elements.",
+	"countmin"       => "The :attribute must have at least :min selected elements.",
 	"different"      => "ะŸะพะปะตั‚ะฐั‚ะฐ :attribute ะธ :other ั‚ั€ัะฑะฒะฐ ะดะฐ ัะฐ ั€ะฐะทะปะธั‡ะฝะธ.",
 	"email"          => "ะŸะพะปะตั‚ะพ :attribute ะต ั ะฝะตะฒะฐะปะธะดะตะฝ ั„ะพั€ะผะฐั‚.",
 	"exists"         => "ะ˜ะทะฑั€ะฐะฝะฐั‚ะฐ ัั‚ะพะนะฝะพัั‚ ะฝะฐ :attribute ะฒะตั‡ะต ััŠั‰ะตัั‚ะฒัƒะฒะฐ.",

+ 5 - 0
application/language/de/validation.php

@@ -24,6 +24,7 @@ return array(
 	"alpha"          => ":attribute darf nur Buchstaben beinhalten.",
 	"alpha_dash"     => ":attribute sollte nur aus Buchstaben, Nummern und Bindestrichen bestehen.",
 	"alpha_num"      => ":attribute sollte nur aus Buchstaben und Nummern bestehen.",
+	"array"          => "The :attribute must have selected elements.",
 	"before"         => ":attribute muss ein Datum vor dem :date sein.",
 	"between"        => array(
 		"numeric" => ":attribute muss zwischen :min und :max liegen.",
@@ -31,6 +32,10 @@ return array(
 		"string"  => ":attribute muss zwischen :min und :max Zeichen lang sein.",
 	),
 	"confirmed"      => ":attribute stimmt nicht mit der Bestätigung überein.",
+	"count"          => "The :attribute must have exactly :count selected elements.",
+	"countbetween"   => "The :attribute must have between :min and :max selected elements.",
+	"countmax"       => "The :attribute must have less than :max selected elements.",
+	"countmin"       => "The :attribute must have at least :min selected elements.",
 	"different"      => ":attribute und :other müssen verschieden sein.",
 	"email"          => ":attribute ist keine gültige Email-Adresse.",
 	"exists"         => "Der gewählte Wert für :attribute ist ungültig.",

+ 5 - 0
application/language/en/validation.php

@@ -24,6 +24,7 @@ return array(
 	"alpha"          => "The :attribute may only contain letters.",
 	"alpha_dash"     => "The :attribute may only contain letters, numbers, and dashes.",
 	"alpha_num"      => "The :attribute may only contain letters and numbers.",
+	"array"          => "The :attribute must have selected elements.",
 	"before"         => "The :attribute must be a date before :date.",
 	"between"        => array(
 		"numeric" => "The :attribute must be between :min - :max.",
@@ -31,6 +32,10 @@ return array(
 		"string"  => "The :attribute must be between :min - :max characters.",
 	),
 	"confirmed"      => "The :attribute confirmation does not match.",
+	"count"          => "The :attribute must have exactly :count selected elements.",
+	"countbetween"   => "The :attribute must have between :min and :max selected elements.",
+	"countmax"       => "The :attribute must have less than :max selected elements.",
+	"countmin"       => "The :attribute must have at least :min selected elements.",
 	"different"      => "The :attribute and :other must be different.",
 	"email"          => "The :attribute format is invalid.",
 	"exists"         => "The selected :attribute is invalid.",

+ 5 - 0
application/language/fr/validation.php

@@ -24,6 +24,7 @@ return array(
 	"alpha"          => "Le champ :attribute ne doit contenir que des lettres.",
 	"alpha_dash"     => "Le champ :attribute ne doit contenir que des lettres, nombres et des tirets.",
 	"alpha_num"      => "Le champ :attribute ne doit contenir que des lettres et nombres.",
+	"array"          => "The :attribute must have selected elements.",
 	"before"         => "Le champ :attribute doit รชtre une date avant :date.",
 	"between"        => array(
 		"numeric" => "Le champ :attribute doit รชtre entre :min - :max.",
@@ -31,6 +32,10 @@ return array(
 		"string"  => "Le champ :attribute doit รชtre entre :min - :max caractรจres.",
 	),
 	"confirmed"      => "Le champ :attribute confirmation est diffรฉrent.",
+	"count"          => "The :attribute must have exactly :count selected elements.",
+	"countbetween"   => "The :attribute must have between :min and :max selected elements.",
+	"countmax"       => "The :attribute must have less than :max selected elements.",
+	"countmin"       => "The :attribute must have at least :min selected elements.",
 	"different"      => "Les champ :attribute et :other doivent รชtre diffรฉrents.",
 	"email"          => "Le format du champ :attribute est invalide.",
 	"exists"         => "Le champ sรฉlectionnรฉ :attribute est invalide.",

+ 5 - 0
application/language/he/validation.php

@@ -27,6 +27,7 @@ return array(
 	"alpha"          => "ื”ืขืจืš :attribute ื™ื›ื•ืœ ืœื”ื›ื™ืœ ืจืง ืื•ืชื™ื•ืช.",
 	"alpha_dash"     => "ื”ืขืจืš :attribute ื™ื›ื•ืœ ืœื”ื›ื™ืœ ืจืง ืื•ืชื™ื•ืช, ืžืกืคืจื™ื ื•ืžืงืคื™ื.",
 	"alpha_num"      => "ื”ืขืจืš :attribute ื™ื›ื•ืœ ืœื”ื›ื™ืœ ืจืง ืื•ืชื™ื•ืช ื•ืžืกืคืจื™ื.",
+	"array"          => "The :attribute must have selected elements.",
 	"before"         => "ื”ืขืจืš :attribute ื—ื™ื™ื‘ ืœื”ื›ื™ืœ ืชืืจื™ืš ืœืคื ื™ :date.",
 	"between"        => array(
 		"numeric" => "ื”ืขืจืš :attribute ื—ื™ื™ื‘ ืœื”ื™ื•ืช ื‘ื™ืŸ :min ืœ-:max.",
@@ -34,6 +35,10 @@ return array(
 		"string"  => "ื”ืขืจืš :attribute ื—ื™ื™ื‘ ืœื”ื›ื™ืœ ื‘ื™ืŸ :min ืœ-:max ืชื•ื•ื™ื.",
 	),
 	"confirmed"      => "ื”ืขืจื›ื™ื ืฉืœ :attribute ื—ื™ื™ื‘ื™ื ืœื”ื™ื•ืช ื–ื”ื™ื.",
+	"count"          => "The :attribute must have exactly :count selected elements.",
+	"countbetween"   => "The :attribute must have between :min and :max selected elements.",
+	"countmax"       => "The :attribute must have less than :max selected elements.",
+	"countmin"       => "The :attribute must have at least :min selected elements.",
 	"different"      => "ื”ืขืจื›ื™ื ืฉืœ :attribute ื•-:other ื—ื™ื™ื‘ื™ื ืœื”ื™ื•ืช ืฉื•ื ื™ื.",
 	"email"          => "ื”ืขืจืš :attribute ื—ื™ื™ื‘ ืœื”ื›ื™ืœ ื›ืชื•ื‘ืช ืื™ืžื™ื™ืœ ืชืงื™ื ื”.",
 	"exists"         => "ื”ืขืจืš :attribute ืœื ืงื™ื™ื.",

+ 5 - 0
application/language/hu/validation.php

@@ -24,6 +24,7 @@ return array(
 	"alpha"          => "A(z) :attribute csak betลฑket tartalmazhat.",
 	"alpha_dash"     => "A(z) :attribute betลฑket, szรกmokat รฉs kรถtล‘jeleket tartalmazhat.",
 	"alpha_num"      => "A(z) :attribute csak betลฑket รฉs szรกmokat tartalmazhat.",
+	"array"          => "The :attribute must have selected elements.",
 	"before"         => "A :attribute :date elล‘tti dรกtum kell legyen.",
 	"between"        => array(
 		"numeric" => "A(z) :attribute :min - :max kรถzรถtti รฉrtรฉk kell legyen.",
@@ -31,6 +32,10 @@ return array(
 		"string"  => "A(z) :attribute :min - :max karakterhossz kรถzรถtt kell legyen",
 	),
 	"confirmed"      => "A(z) :attribute megerล‘sรญtรฉse nem egyezett meg.",
+	"count"          => "The :attribute must have exactly :count selected elements.",
+	"countbetween"   => "The :attribute must have between :min and :max selected elements.",
+	"countmax"       => "The :attribute must have less than :max selected elements.",
+	"countmin"       => "The :attribute must have at least :min selected elements.",
 	"different"      => "A(z) :attribute รฉs :other kรผlรถnbรถzล‘ kell legyen.",
 	"email"          => "A(z) :attribute formรกtuma nem megfelelล‘.",
 	"exists"         => "A(z) vรกlasztott :attribute nem megfelelล‘.",

+ 5 - 0
application/language/id/validation.php

@@ -24,6 +24,7 @@ return array(
 	"alpha"          => "Isian :attribute hanya boleh berisi huruf.",
 	"alpha_dash"     => "Isian :attribute hanya boleh berisi huruf, angka, dan strip.",
 	"alpha_num"      => "Isian :attribute hanya boleh berisi huruf dan angka.",
+	"array"          => "The :attribute must have selected elements.",
 	"before"         => "Isian :attribute harus tanggal sebelum :date.",
 	"between"        => array(
 		"numeric" => "Isian :attribute harus antara :min - :max.",
@@ -31,6 +32,10 @@ return array(
 		"string"  => "Isian :attribute harus antara  :min - :max karakter.",
 	),
 	"confirmed"      => "Konfirmasi :attribute tidak cocok.",
+	"count"          => "The :attribute must have exactly :count selected elements.",
+	"countbetween"   => "The :attribute must have between :min and :max selected elements.",
+	"countmax"       => "The :attribute must have less than :max selected elements.",
+	"countmin"       => "The :attribute must have at least :min selected elements.",
 	"different"      => "Isian :attribute dan :other harus berbeda.",
 	"email"          => "Format isian :attribute tidak valid.",
 	"exists"         => "Isian :attribute yang dipilih tidak valid.",

+ 5 - 0
application/language/ja/validation.php

@@ -40,6 +40,7 @@ return array(
 	"alpha"          => ":attributeใฏใ‚ขใƒซใƒ•ใ‚กใƒ™ใƒƒใƒ‰ใฎใฟใŒใ”ๅˆฉ็”จใงใใพใ™ใ€‚",
 	"alpha_dash"     => ":attributeใฏ่‹ฑๆ•ฐๅญ—ใจใƒ€ใƒƒใ‚ทใƒฅ(-)ๅŠใณไธ‹็ทš(_)ใŒใ”ๅˆฉ็”จใงใใพใ™ใ€‚",
 	"alpha_num"      => ":attributeใฏ่‹ฑๆ•ฐๅญ—ใŒใ”ๅˆฉ็”จใงใใพใ™ใ€‚",
+	"array"          => "The :attribute must have selected elements.",
 	"before"         => ":attributeใซใฏใ€:dateไปฅๅ‰ใฎๆ—ฅไป˜ใ‚’ใ”ๅˆฉ็”จใใ ใ•ใ„ใ€‚",
 	"between"        => array(
 		"numeric" => ":attributeใฏใ€:minใ‹ใ‚‰ใ€:maxใพใงใฎๆ•ฐๅญ—ใ‚’ใ”ๆŒ‡ๅฎšใใ ใ•ใ„ใ€‚",
@@ -47,6 +48,10 @@ return array(
 		"string"  => ":attributeใฏใ€:minๆ–‡ๅญ—ใ‹ใ‚‰:maxๆ–‡ๅญ—ใฎ้–“ใงใ”ๆŒ‡ๅฎšใใ ใ•ใ„ใ€‚",
 	),
 	"confirmed"      => ":attributeใจใ€็ขบ่ชใƒ•ใ‚ฃใƒผใƒซใƒ‰ใจใŒใ€ไธ€่‡ดใ—ใฆใ„ใพใ›ใ‚“ใ€‚",
+	"count"          => "The :attribute must have exactly :count selected elements.",
+	"countbetween"   => "The :attribute must have between :min and :max selected elements.",
+	"countmax"       => "The :attribute must have less than :max selected elements.",
+	"countmin"       => "The :attribute must have at least :min selected elements.",
 	"different"      => ":attributeใจ:otherใซใฏใ€็•ฐใชใฃใŸๅ†…ๅฎนใ‚’ๆŒ‡ๅฎšใ—ใฆใใ ใ•ใ„ใ€‚",
 	"email"          => ":attributeใซใฏๆญฃใ—ใ„ใƒกใƒผใƒซใ‚ขใƒ‰ใƒฌใ‚นใฎๅฝขๅผใ‚’ใ”ๆŒ‡ๅฎšใใ ใ•ใ„ใ€‚",
 	"exists"         => "้ธๆŠžใ•ใ‚ŒใŸ:attributeใฏๆญฃใ—ใใ‚ใ‚Šใพใ›ใ‚“ใ€‚",

+ 5 - 0
application/language/nl/validation.php

@@ -15,6 +15,7 @@ return array(
 	"alpha"          => "Het :attribute mag alleen letters bevatten.",
 	"alpha_dash"     => "Het :attribute mag alleen letters, nummers, onderstreep(_) en strepen(-) bevatten.",
 	"alpha_num"      => "Het :attribute mag alleen letters en nummers",
+	"array"          => "The :attribute must have selected elements.",
 	"before"         => "Het :attribute moet een datum voor :date zijn.",
 	"between"        => array(
 		"numeric" => "Het :attribute moet tussen :min en :max zijn.",
@@ -22,6 +23,10 @@ return array(
 		"string"  => "Het :attribute moet tussen :min en :max tekens zijn.",
 	),
 	"confirmed"      => "Het :attribute bevestiging komt niet overeen.",
+	"count"          => "The :attribute must have exactly :count selected elements.",
+	"countbetween"   => "The :attribute must have between :min and :max selected elements.",
+	"countmax"       => "The :attribute must have less than :max selected elements.",
+	"countmin"       => "The :attribute must have at least :min selected elements.",
 	"different"      => "Het :attribute en :other moeten verschillend zijn.",
 	"email"          => "Het :attribute formaat is ongeldig.",
 	"exists"         => "Het gekozen :attribute is al ingebruik.",

+ 93 - 88
application/language/pl/validation.php

@@ -2,98 +2,103 @@
 
 return array(
 
-    /*
-    |--------------------------------------------------------------------------
-    | Validation Language Lines
-    |--------------------------------------------------------------------------
-    |
-    | The following language lines contain the default error messages used
-    | by the validator class. Some of the rules contain multiple versions,
-    | such as the size (max, min, between) rules. These versions are used
-    | for different input types such as strings and files.
-    |
-    | These language lines may be easily changed to provide custom error
-    | messages in your application. Error messages for custom validation
-    | rules may also be added to this file.
-    |
-    */
+	/*
+	|--------------------------------------------------------------------------
+	| Validation Language Lines
+	|--------------------------------------------------------------------------
+	|
+	| The following language lines contain the default error messages used
+	| by the validator class. Some of the rules contain multiple versions,
+	| such as the size (max, min, between) rules. These versions are used
+	| for different input types such as strings and files.
+	|
+	| These language lines may be easily changed to provide custom error
+	| messages in your application. Error messages for custom validation
+	| rules may also be added to this file.
+	|
+	*/
 
-    "accepted"       => ":attribute musi zostaฤ‡ zaakceptowane.",
-    "active_url"     => ":attribute nie jest prawidล‚owym adresem URL.",
-    "after"          => ":attribute musi zawieraฤ‡ datฤ™, ktรณra jest po :date.",
-    "alpha"          => ":attribute moลผe zawieraฤ‡ jedynie litery.",
-    "alpha_dash"     => ":attribute moลผe zawieraฤ‡ jedynie litery, cyfry i myล›lniki.",
-    "alpha_num"      => ":attribute moลผe zawieraฤ‡ jedynie litery i cyfry.",
-    "before"         => ":attribute musi zawieraฤ‡ datฤ™, ktรณra jest przed :date.",
-    "between"        => array(
-        "numeric" => ":ttribute musi mieล›ciฤ‡ siฤ™ w granicach :min - :max.",
-        "file"    => ":attribute musi mieฤ‡ :min - :max kilobajtรณw.",
-        "string"  => ":attribute musi mieฤ‡ :min - :max znakรณw.",
-    ),
-    "confirmed"      => "Potwierdzenie :attribute siฤ™ nie zgadza.",
-    "different"      => ":attribute i :other muszฤ… siฤ™ od siebie rรณลผniฤ‡.",
-    "email"          => "The :attribute format is invalid.",
-    "exists"         => "Zaznaczona opcja :attribute jest nieprawidล‚owa.",
-    "image"          => ":attribute musi byฤ‡ obrazkiem.",
-    "in"             => "Zaznaczona opcja :attribute jest nieprawidล‚owa.",
-    "integer"        => ":attribute musi byฤ‡ liczbฤ… caล‚kowitฤ….",
-    "ip"             => ":attribute musi byฤ‡ prawidล‚owym adresem IP.",
-    "match"          => "Format :attribute jest nieprawidล‚owy.",
-    "max"            => array(
-        "numeric" => ":attribute musi byฤ‡ poniลผej :max.",
-        "file"    => ":attribute musi mieฤ‡ poniลผej :max kilobajtรณw.",
-        "string"  => ":attribute musi mieฤ‡ poniลผej :max znakรณw.",
-    ),
-    "mimes"          => ":attribute musi byฤ‡ plikiem rodzaju :values.",
-    "min"            => array(
-        "numeric" => ":attribute musi byฤ‡ co najmniej :min.",
-        "file"    => "Plik :attribute musi mieฤ‡ co najmniej :min kilobajtรณw.",
-        "string"  => ":attribute musi mieฤ‡ co najmniej :min znakรณw.",
-    ),
-    "not_in"         => "Zaznaczona opcja :attribute jest nieprawidล‚owa.",
-    "numeric"        => ":attribute musi byฤ‡ numeryczne.",
-    "required"       => "Pole :attribute jest wymagane.",
-    "same"           => ":attribute i :other muszฤ… byฤ‡ takie same.",
-    "size"           => array(
-        "numeric" => ":attribute musi mieฤ‡ rozmiary :size.",
-        "file"    => ":attribute musi mieฤ‡ :size kilobajtรณw.",
-        "string"  => ":attribute musi mieฤ‡ :size znakรณw.",
-    ),
-    "unique"         => ":attribute zostaล‚o juลผ uลผyte.",
-    "url"            => "Format pola :attribute jest nieprawidล‚owy.",
+	"accepted"       => ":attribute musi zostaฤ‡ zaakceptowane.",
+	"active_url"     => ":attribute nie jest prawidล‚owym adresem URL.",
+	"after"          => ":attribute musi zawieraฤ‡ datฤ™, ktรณra jest po :date.",
+	"alpha"          => ":attribute moลผe zawieraฤ‡ jedynie litery.",
+	"alpha_dash"     => ":attribute moลผe zawieraฤ‡ jedynie litery, cyfry i myล›lniki.",
+	"alpha_num"      => ":attribute moลผe zawieraฤ‡ jedynie litery i cyfry.",
+	"array"          => "The :attribute must have selected elements.",
+	"before"         => ":attribute musi zawieraฤ‡ datฤ™, ktรณra jest przed :date.",
+	"between"        => array(
+		"numeric" => ":attribute musi mieล›ciฤ‡ siฤ™ w granicach :min - :max.",
+		"file"    => ":attribute musi mieฤ‡ :min - :max kilobajtรณw.",
+		"string"  => ":attribute musi mieฤ‡ :min - :max znakรณw.",
+	),
+	"confirmed"      => "Potwierdzenie :attribute siฤ™ nie zgadza.",
+	"count"          => "The :attribute must have exactly :count selected elements.",
+	"countbetween"   => "The :attribute must have between :min and :max selected elements.",
+	"countmax"       => "The :attribute must have less than :max selected elements.",
+	"countmin"       => "The :attribute must have at least :min selected elements.",
+	"different"      => ":attribute i :other muszฤ… siฤ™ od siebie rรณลผniฤ‡.",
+	"email"          => "The :attribute format is invalid.",
+	"exists"         => "Zaznaczona opcja :attribute jest nieprawidล‚owa.",
+	"image"          => ":attribute musi byฤ‡ obrazkiem.",
+	"in"             => "Zaznaczona opcja :attribute jest nieprawidล‚owa.",
+	"integer"        => ":attribute musi byฤ‡ liczbฤ… caล‚kowitฤ….",
+	"ip"             => ":attribute musi byฤ‡ prawidล‚owym adresem IP.",
+	"match"          => "Format :attribute jest nieprawidล‚owy.",
+	"max"            => array(
+		"numeric" => ":attribute musi byฤ‡ poniลผej :max.",
+		"file"    => ":attribute musi mieฤ‡ poniลผej :max kilobajtรณw.",
+		"string"  => ":attribute musi mieฤ‡ poniลผej :max znakรณw.",
+	),
+	"mimes"          => ":attribute musi byฤ‡ plikiem rodzaju :values.",
+	"min"            => array(
+		"numeric" => ":attribute musi byฤ‡ co najmniej :min.",
+		"file"    => "Plik :attribute musi mieฤ‡ co najmniej :min kilobajtรณw.",
+		"string"  => ":attribute musi mieฤ‡ co najmniej :min znakรณw.",
+	),
+	"not_in"         => "Zaznaczona opcja :attribute jest nieprawidล‚owa.",
+	"numeric"        => ":attribute musi byฤ‡ numeryczne.",
+	"required"       => "Pole :attribute jest wymagane.",
+	"same"           => ":attribute i :other muszฤ… byฤ‡ takie same.",
+	"size"           => array(
+		"numeric" => ":attribute musi mieฤ‡ rozmiary :size.",
+		"file"    => ":attribute musi mieฤ‡ :size kilobajtรณw.",
+		"string"  => ":attribute musi mieฤ‡ :size znakรณw.",
+	),
+	"unique"         => ":attribute zostaล‚o juลผ uลผyte.",
+	"url"            => "Format pola :attribute jest nieprawidล‚owy.",
 
-    /*
-    |--------------------------------------------------------------------------
-    | Custom Validation Language Lines
-    |--------------------------------------------------------------------------
-    |
-    | Here you may specify custom validation messages for attributes using the
-    | convention "attribute_rule" to name the lines. This helps keep your
-    | custom validation clean and tidy.
-    |
-    | So, say you want to use a custom validation message when validating that
-    | the "email" attribute is unique. Just add "email_unique" to this array
-    | with your custom message. The Validator will handle the rest!
-    |
-    */
+	/*
+	|--------------------------------------------------------------------------
+	| Custom Validation Language Lines
+	|--------------------------------------------------------------------------
+	|
+	| Here you may specify custom validation messages for attributes using the
+	| convention "attribute_rule" to name the lines. This helps keep your
+	| custom validation clean and tidy.
+	|
+	| So, say you want to use a custom validation message when validating that
+	| the "email" attribute is unique. Just add "email_unique" to this array
+	| with your custom message. The Validator will handle the rest!
+	|
+	*/
 
-    'custom' => array(),
+	'custom' => array(),
 
-    /*
-    |--------------------------------------------------------------------------
-    | Validation Attributes
-    |--------------------------------------------------------------------------
-    |
-    | The following language lines are used to swap attribute place-holders
-    | with something more reader friendly such as "E-Mail Address" instead
-    | of "email". Your users will thank you.
-    |
-    | The Validator class will automatically search this array of lines it
-    | is attempting to replace the :attribute place-holder in messages.
-    | It's pretty slick. We think you'll like it.
-    |
-    */
+	/*
+	|--------------------------------------------------------------------------
+	| Validation Attributes
+	|--------------------------------------------------------------------------
+	|
+	| The following language lines are used to swap attribute place-holders
+	| with something more reader friendly such as "E-Mail Address" instead
+	| of "email". Your users will thank you.
+	|
+	| The Validator class will automatically search this array of lines it
+	| is attempting to replace the :attribute place-holder in messages.
+	| It's pretty slick. We think you'll like it.
+	|
+	*/
 
-    'attributes' => array(),
+	'attributes' => array(),
 
 );

+ 5 - 0
application/language/ru/validation.php

@@ -24,6 +24,7 @@ return array(
 	"alpha"          => "ะŸะพะปะต :attribute ะผะพะถะตั‚ ัะพะดะตั€ะถะฐั‚ัŒ ั‚ะพะปัŒะบะพ ะฑัƒะบะฒั‹.",
 	"alpha_dash"     => "ะŸะพะปะต :attribute ะผะพะถะตั‚ ัะพะดะตั€ะถะฐั‚ัŒ ั‚ะพะปัŒะบะพ ะฑัƒะบะฒั‹, ั†ะธั„ั€ั‹ ะธ ั‚ะธั€ะต.",
 	"alpha_num"      => "ะŸะพะปะต :attribute ะผะพะถะตั‚ ัะพะดะตั€ะถะฐั‚ัŒ ั‚ะพะปัŒะบะพ ะฑัƒะบะฒั‹ ะธ ั†ะธั„ั€ั‹.",
+	"array"          => "The :attribute must have selected elements.",
 	"before"         => "ะŸะพะปะต :attribute ะดะพะปะถะฝะพ ะฑั‹ั‚ัŒ ะดะฐั‚ะพะน ะฟะตั€ะตะด :date.",
 	"between"        => array(
 		"numeric" => "ะŸะพะปะต :attribute ะดะพะปะถะฝะพ ะฑั‹ั‚ัŒ ะผะตะถะดัƒ :min ะธ :max.",
@@ -31,6 +32,10 @@ return array(
 		"string"  => "ะŸะพะปะต :attribute ะดะพะปะถะฝะพ ะฑั‹ั‚ัŒ ะพั‚ :min ะดะพ :max ัะธะผะฒะพะปะพะฒ.",
 	),
 	"confirmed"      => "ะŸะพะปะต :attribute ะฝะต ัะพะฒะฟะฐะดะฐะตั‚ ั ะฟะพะดั‚ะฒะตั€ะถะดะตะฝะธะตะผ.",
+	"count"          => "The :attribute must have exactly :count selected elements.",
+	"countbetween"   => "The :attribute must have between :min and :max selected elements.",
+	"countmax"       => "The :attribute must have less than :max selected elements.",
+	"countmin"       => "The :attribute must have at least :min selected elements.",
 	"different"      => "ะŸะพะปั :attribute ะธ :other ะดะพะปะถะฝั‹ ั€ะฐะทะปะธั‡ะฐั‚ัŒัั.",
 	"email"          => "ะŸะพะปะต :attribute ะธะผะตะตั‚ ะฝะตะฒะตั€ะฝั‹ะน ั„ะพั€ะผะฐั‚.",
 	"exists"         => "ะ’ั‹ะฑั€ะฐะฝะฝะพะต ะทะฝะฐั‡ะตะฝะธะต ะดะปั :attribute ัƒะถะต ััƒั‰ะตัั‚ะฒัƒะตั‚.",

+ 28 - 0
application/language/tr/pagination.php

@@ -0,0 +1,28 @@
+<?php 
+
+/**
+ * Laravel - A PHP Framework For Web Artisans
+ *
+ * @package  Language
+ * @version  3.2.3
+ * @author   Sinan Eldem <sinan@sinaneldem.com.tr>
+ * @link     http://sinaneldem.com.tr
+ */
+
+return array(
+
+	/*
+	|--------------------------------------------------------------------------
+	| Pagination Language Lines
+	|--------------------------------------------------------------------------
+	|
+	| The following language lines are used by the paginator library to build
+	| the pagination links. You're free to change them to anything you want.
+	| If you come up with something more exciting, let us know.
+	|
+	*/
+
+	'previous' => '&laquo; ร–nceki',
+	'next'     => 'Sonraki &raquo;',
+
+);

+ 108 - 0
application/language/tr/validation.php

@@ -0,0 +1,108 @@
+<?php 
+
+/**
+ * Laravel - A PHP Framework For Web Artisans
+ *
+ * @package  Language
+ * @version  3.2.3
+ * @author   Sinan Eldem <sinan@sinaneldem.com.tr>
+ * @link     http://sinaneldem.com.tr
+ */
+
+return array(
+
+	/*
+	|--------------------------------------------------------------------------
+	| Validation Language Lines
+	|--------------------------------------------------------------------------
+	|
+	| The following language lines contain the default error messages used
+	| by the validator class. Some of the rules contain multiple versions,
+	| such as the size (max, min, between) rules. These versions are used
+	| for different input types such as strings and files.
+	|
+	| These language lines may be easily changed to provide custom error
+	| messages in your application. Error messages for custom validation
+	| rules may also be added to this file.
+	|
+	*/
+
+	"accepted"       => ":attribute kabul edilmelidir.",
+	"active_url"     => ":attribute geรงerli bir URL olmalฤฑdฤฑr.",
+	"after"          => ":attribute ลŸundan daha eski bir tarih olmalฤฑdฤฑr :date.",
+	"alpha"          => ":attribute sadece harflerden oluลŸmalฤฑdฤฑr.",
+	"alpha_dash"     => ":attribute sadece harfler, rakamlar ve tirelerden oluลŸmalฤฑdฤฑr.",
+	"alpha_num"      => ":attribute sadece harfler ve rakamlar iรงermelidir.",
+	"before"         => ":attribute ลŸundan daha รถnceki bir tarih olmalฤฑdฤฑr :date.",
+	"between"        => array(
+		"numeric" => ":attribute :min - :max arasฤฑnda olmalฤฑdฤฑr.",
+		"file"    => ":attribute :min - :max arasฤฑndaki kilobyte deฤŸeri olmalฤฑdฤฑr.",
+		"string"  => ":attribute :min - :max arasฤฑnda karakterden oluลŸmalฤฑdฤฑr.",
+	),
+	"confirmed"      => ":attribute onayฤฑ eลŸleลŸmiyor.",
+	"different"      => ":attribute ile :other birbirinden farklฤฑ olmalฤฑdฤฑr.",
+	"email"          => ":attribute biรงimi geรงersiz.",
+	"exists"         => "Seรงili :attribute geรงersiz.",
+	"image"          => ":attribute resim dosyasฤฑ olmalฤฑdฤฑr.",
+	"in"             => "selected :attribute geรงersiz.",
+	"integer"        => ":attribute rakam olmalฤฑdฤฑr.",
+	"ip"             => ":attribute geรงerli bir IP adresi olmalฤฑdฤฑr.",
+	"match"          => ":attribute biรงimi geรงersiz.",
+	"max"            => array(
+		"numeric" => ":attribute ลŸundan kรผรงรผk olmalฤฑdฤฑr :max.",
+		"file"    => ":attribute ลŸundan kรผรงรผk olmalฤฑdฤฑr :max kilobyte.",
+		"string"  => ":attribute ลŸundan kรผรงรผk olmalฤฑdฤฑr :max karakter.",
+	),
+	"mimes"          => ":attribute dosya biรงimi :values olmalฤฑdฤฑr.",
+	"min"            => array(
+		"numeric" => ":attribute en az :min olmalฤฑdฤฑr.",
+		"file"    => ":attribute en az :min kilobyte olmalฤฑdฤฑr.",
+		"string"  => ":attribute en az :min karakter olmalฤฑdฤฑr.",
+	),
+	"not_in"         => "Seรงili :attribute geรงersiz.",
+	"numeric"        => ":attribute rakam olmalฤฑdฤฑr.",
+	"required"       => ":attribute alanฤฑ gereklidir.",
+	"same"           => ":attribute ile :other eลŸleลŸmelidir.",
+	"size"           => array(
+		"numeric" => ":attribute :size olmalฤฑdฤฑr.",
+		"file"    => ":attribute :size kilobyte olmalฤฑdฤฑr.",
+		"string"  => ":attribute :size karakter olmalฤฑdฤฑr.",
+	),
+	"unique"         => ":attribute daha รถnceden kayฤฑt edilmiลŸ.",
+	"url"            => ":attribute biรงimi geรงersiz.",
+
+	/*
+	|--------------------------------------------------------------------------
+	| Custom Validation Language Lines
+	|--------------------------------------------------------------------------
+	|
+	| Here you may specify custom validation messages for attributes using the
+	| convention "attribute_rule" to name the lines. This helps keep your
+	| custom validation clean and tidy.
+	|
+	| So, say you want to use a custom validation message when validating that
+	| the "email" attribute is unique. Just add "email_unique" to this array
+	| with your custom message. The Validator will handle the rest!
+	|
+	*/
+
+	'custom' => array(),
+
+	/*
+	|--------------------------------------------------------------------------
+	| Validation Attributes
+	|--------------------------------------------------------------------------
+	|
+	| The following language lines are used to swap attribute place-holders
+	| with something more reader friendly such as "E-Mail Address" instead
+	| of "email". Your users will thank you.
+	|
+	| The Validator class will automatically search this array of lines it
+	| is attempting to replace the :attribute place-holder in messages.
+	| It's pretty slick. We think you'll like it.
+	|
+	*/
+
+	'attributes' => array(),
+
+);

+ 12 - 0
laravel/bundle.php

@@ -461,4 +461,16 @@ class Bundle {
 		return array_keys(static::$bundles);
 	}
 
+	/**
+	 * Expand given bundle path of form "[bundle::]path/...".
+	 *
+	 * @param  string  $path
+	 * @return string
+	 */
+	public static function expand($path)
+	{
+		list($bundle, $element) = static::parse($path);
+		return static::path($bundle).$element;
+	}
+
 }

+ 0 - 24
laravel/cli/tasks/test/phpunit.php

@@ -1,12 +1,4 @@
 <?php
-/**
- * Laravel - A PHP Framework For Web Artisans
- *
- * @package  Laravel
- * @version  3.0.0
- * @author   Taylor Otwell <taylorotwell@gmail.com>
- * @link     http://laravel.com
- */
 
 // --------------------------------------------------------------
 // Define the directory separator for the environment.
@@ -18,22 +10,6 @@ define('DS', DIRECTORY_SEPARATOR);
 // --------------------------------------------------------------
 require 'paths.php';
 
-// --------------------------------------------------------------
-// Override the application paths when testing the core.
-// --------------------------------------------------------------
-$config = file_get_contents('phpunit.xml');
-
-if (strpos($config, 'laravel-tests') !== false)
-{
-	$path = path('bundle').'laravel-tests'.DS;
-
-	set_path('app', $path.'application'.DS);
-
-	set_path('bundle', $path.'bundles'.DS);
-
-	set_path('storage', $path.'storage'.DS);
-}
-
 // --------------------------------------------------------------
 // Bootstrap the Laravel core.
 // --------------------------------------------------------------

+ 23 - 20
laravel/cli/tasks/test/runner.php

@@ -7,6 +7,15 @@ use Laravel\CLI\Tasks\Task;
 
 class Runner extends Task {
 
+	/**
+	 * The base directory where the tests will be executed.
+	 *
+	 * A phpunit.xml should also be stored in that directory.
+	 * 
+	 * @var string
+	 */
+	protected $base_path;
+
 	/**
 	 * Run all of the unit tests for the application.
 	 *
@@ -27,17 +36,8 @@ class Runner extends Task {
 	 */
 	public function core()
 	{
-		if ( ! is_dir(path('bundle').'laravel-tests'))
-		{
-			throw new \Exception("The bundle [laravel-tests] has not been installed!");
-		}
-
-		// When testing the Laravel core, we will just stub the path directly
-		// so the test bundle is not required to be registered in the bundle
-		// configuration, as it is kind of a unique bundle.
-		$this->stub(path('bundle').'laravel-tests/cases');
-
-		$path = path('bundle').'laravel-tests/';
+		$this->base_path = path('sys').'tests'.DS;
+		$this->stub(path('sys').'tests'.DS.'cases');
 
 		$this->test();
 	}
@@ -55,6 +55,8 @@ class Runner extends Task {
 			$bundles = Bundle::names();
 		}
 
+		$this->base_path = path('sys').'cli'.DS.'tasks'.DS.'test'.DS;
+
 		foreach ($bundles as $bundle)
 		{
 			// To run PHPUnit for the application, bundles, and the framework
@@ -78,17 +80,20 @@ class Runner extends Task {
 	protected function test()
 	{
 		// We'll simply fire off PHPUnit with the configuration switch
-		// pointing to our temporary configuration file. This allows
+		// pointing to our requested configuration file. This allows
 		// us to flexibly run tests for any setup.
-		$path = path('base').'phpunit.xml';
+		$path = 'phpunit.xml';
 		
 		// fix the spaced directories problem when using the command line
 		// strings with spaces inside should be wrapped in quotes.
 		$path = escapeshellarg($path);
 
-		passthru('phpunit --configuration '.$path);
+		passthru('phpunit --configuration '.$path, $status);
 
 		@unlink($path);
+
+		// Pass through the exit status
+		exit($status);
 	}
 
 	/**
@@ -108,7 +113,7 @@ class Runner extends Task {
 		// locations depending on what the developer wants to test.
 		foreach (array('bootstrap', 'directory') as $item)
 		{
-			$stub = $this->{"swap_{$item}"}($stub, $path, $directory);
+			$stub = $this->{"swap_{$item}"}($stub, $directory);
 		}
 
 		File::put(path('base').'phpunit.xml', $stub);
@@ -118,24 +123,22 @@ class Runner extends Task {
 	 * Swap the bootstrap file in the stub.
 	 *
 	 * @param  string  $stub
-	 * @param  string  $path
 	 * @param  string  $directory
 	 * @return string
 	 */
-	protected function swap_bootstrap($stub, $path, $directory)
+	protected function swap_bootstrap($stub, $directory)
 	{
-		return str_replace('{{bootstrap}}', $path.'phpunit.php', $stub);
+		return str_replace('{{bootstrap}}', $this->base_path.'phpunit.php', $stub);
 	}
 
 	/**
 	 * Swap the directory in the stub.
 	 *
 	 * @param  string  $stub
-	 * @param  string  $path
 	 * @param  string  $directory
 	 * @return string
 	 */
-	protected function swap_directory($stub, $path, $directory)
+	protected function swap_directory($stub, $directory)
 	{
 		return str_replace('{{directory}}', $directory, $stub);
 	}

+ 14 - 0
laravel/core.php

@@ -17,6 +17,20 @@ define('BLADE_EXT', '.blade.php');
 define('DEFAULT_BUNDLE', 'application');
 define('MB_STRING', (int) function_exists('mb_get_info'));
 
+/*
+|--------------------------------------------------------------------------
+| Start Output Buffering
+|--------------------------------------------------------------------------
+|
+| Output buffering allows us to capture all output at any time, so that we
+| can discard it or treat it accordingly. An example of this is if you have
+| echoed a string, but want to return a Redirect object. Because Symfony
+| only checks if headers have been sent, your redirect just silently fails.
+|
+*/
+
+ob_start('mb_output_handler');
+
 /*
 |--------------------------------------------------------------------------
 | Require Core Classes

+ 15 - 16
laravel/database/eloquent/query.php

@@ -38,7 +38,7 @@ class Query {
 	);
 
 	/**
-	 * Create a new query instance for a model.
+	 * Creat a new query instance for a model.
 	 *
 	 * @param  Model  $model
 	 * @return void
@@ -118,7 +118,7 @@ class Query {
 			$new = new $class(array(), true);
 
 			// We need to set the attributes manually in case the accessible property is
-			// set on the array which will prevent the mass assignment of attributes if
+			// set on the array which will prevent the mass assignemnt of attributes if
 			// we were to pass them in using the constructor or fill methods.
 			$new->fill_raw($result);
 
@@ -141,7 +141,7 @@ class Query {
 			}
 		}
 
-		// The many to many relationships may have pivot table columns on them
+		// The many to many relationships may have pivot table column on them
 		// so we will call the "clean" method on the relationship to remove
 		// any pivot columns that are on the model.
 		if ($this instanceof Relationships\Has_Many_And_Belongs_To)
@@ -199,7 +199,7 @@ class Query {
 		foreach ($this->model_includes() as $include => $constraints)
 		{
 			// To get the nested includes, we want to find any includes that begin
-			// the relationship with a dot, then we will strip off the leading
+			// the relationship and a dot, then we will strip off the leading
 			// nesting indicator and set the include in the array.
 			if (starts_with($include, $relationship.'.'))
 			{
@@ -217,23 +217,22 @@ class Query {
 	 */
 	protected function model_includes()
 	{
-		$relationships = array_keys($this->model->includes);
-		$implicits = array();
+		$includes = array();
 
-		foreach ($relationships as $relationship)
+		foreach ($this->model->includes as $relationship => $constraints)
 		{
-			$parts = explode('.', $relationship);
-
-			$prefix = '';
-			foreach ($parts as $part)
+			// When eager loading relationships, constraints may be set on the eager
+			// load definition; however, is none are set, we need to swap the key
+			// and the value of the array since there are no constraints.
+			if (is_numeric($relationship))
 			{
-				$implicits[$prefix.$part] = NULL;
-				$prefix .= $part.'.';
+				list($relationship, $constraints) = array($constraints, null);
 			}
+
+			$includes[$relationship] = $constraints;
 		}
 
-		// Add all implicit includes to the explicit ones
-		return $this->model->includes + $implicits;
+		return $includes;
 	}
 
 	/**
@@ -278,4 +277,4 @@ class Query {
 		return $this;
 	}
 
-}
+}

+ 32 - 16
laravel/database/query.php

@@ -2,7 +2,7 @@
 
 use Closure;
 use Laravel\Database;
-use Paginator;
+use Laravel\Paginator;
 use Laravel\Database\Query\Grammars\Postgres;
 use Laravel\Database\Query\Grammars\SQLServer;
 
@@ -140,7 +140,7 @@ class Query {
 	 */
 	public function select($columns = array('*'))
 	{
-		$this->selects = is_array($columns) ? $columns : array($columns);
+		$this->selects = (array) $columns;
 		return $this;
 	}
 
@@ -158,7 +158,7 @@ class Query {
 	{
 		// If the "column" is really an instance of a Closure, the developer is
 		// trying to create a join with a complex "ON" clause. So, we will add
-		// the join, and then call the Closure with the join.
+		// the join, and then call the Closure with the join/
 		if ($column1 instanceof Closure)
 		{
 			$this->joins[] = new Query\Join($type, $table);
@@ -168,7 +168,7 @@ class Query {
 
 		// If the column is just a string, we can assume that the join just
 		// has a simple on clause, and we'll create the join instance and
-		// add the clause automatically for the developer.
+		// add the clause automatically for the develoepr.
 		else
 		{
 			$join = new Query\Join($type, $table);
@@ -283,7 +283,7 @@ class Query {
 	 */
 	public function or_where_id($value)
 	{
-		return $this->or_where('id', '=', $value);
+		return $this->or_where('id', '=', $value);		
 	}
 
 	/**
@@ -395,7 +395,7 @@ class Query {
 	}
 
 	/**
-	 * Add nested constraints to the query.
+	 * Add a nested where condition to the query.
 	 *
 	 * @param  Closure  $callback
 	 * @param  string   $connector
@@ -403,7 +403,24 @@ class Query {
 	 */
 	public function where_nested($callback, $connector = 'AND')
 	{
-		call_user_func($callback, $this);
+		$type = 'where_nested';
+
+		// To handle a nested where statement, we will actually instantiate a new
+		// Query instance and run the callback over that instance, which will
+		// allow the developer to have a fresh query instance
+		$query = new Query($this->connection, $this->grammar, $this->from);
+
+		call_user_func($callback, $query);
+
+		// Once the callback has been run on the query, we will store the nested
+		// query instance on the where clause array so that it's passed to the
+		// query's query grammar instance when building.
+		if ($query->wheres !== null)
+		{
+			$this->wheres[] = compact('type', 'query', 'connector');
+		}
+
+		$this->bindings = array_merge($this->bindings, $query->bindings);
 
 		return $this;
 	}
@@ -436,7 +453,7 @@ class Query {
 
 		foreach ($segments as $segment)
 		{
-			// If the segment is not a boolean connector, we can assume it is
+			// If the segment is not a boolean connector, we can assume it it is
 			// a column name, and we'll add it to the query as a new constraint
 			// of the query's where clause and keep iterating the segments.
 			if ($segment != '_and_' and $segment != '_or_')
@@ -475,7 +492,6 @@ class Query {
 	 * @param  string  $column
 	 * @param  string  $operator
 	 * @param  mixed   $value
-	 * @return Query
 	 */
 	public function having($column, $operator, $value)
 	{
@@ -660,7 +676,7 @@ class Query {
 	public function aggregate($aggregator, $columns)
 	{
 		// We'll set the aggregate value so the grammar does not try to compile
-		// a SELECT clause on the query. If an aggregator is present, its own
+		// a SELECT clause on the query. If an aggregator is present, it's own
 		// grammar function will be used to build the SQL syntax.
 		$this->aggregate = compact('aggregator', 'columns');
 
@@ -687,7 +703,7 @@ class Query {
 	{
 		// Because some database engines may throw errors if we leave orderings
 		// on the query when retrieving the total number of records, we'll drop
-		// all of the orderings and put them back on the query.
+		// all of the ordreings and put them back on the query.
 		list($orderings, $this->orderings) = array($this->orderings, null);
 
 		$total = $this->count(reset($columns));
@@ -714,12 +730,12 @@ class Query {
 	{
 		// Force every insert to be treated like a batch insert to make creating
 		// the binding array simpler since we can just spin through the inserted
-		// rows as if there was more than one every time.
+		// rows as if there/ was more than one every time.
 		if ( ! is_array(reset($values))) $values = array($values);
 
 		$bindings = array();
 
-		// We need to merge the insert values into the array of the query
+		// We need to merge the the insert values into the array of the query
 		// bindings so that they will be bound to the PDO statement when it
 		// is executed by the database connection.
 		foreach ($values as $value)
@@ -820,7 +836,7 @@ class Query {
 	/**
 	 * Execute the query as a DELETE statement.
 	 *
-	 * Optionally, an ID may be passed to the method to delete a specific row.
+	 * Optionally, an ID may be passed to the method do delete a specific row.
 	 *
 	 * @param  int   $id
 	 * @return int
@@ -837,7 +853,7 @@ class Query {
 
 		$sql = $this->grammar->delete($this);
 
-		return $this->connection->query($sql, $this->bindings);
+		return $this->connection->query($sql, $this->bindings);		
 	}
 
 	/**
@@ -853,7 +869,7 @@ class Query {
 		}
 
 		// All of the aggregate methods are handled by a single method, so we'll
-		// catch them all here and then pass them off to the aggregate method
+		// catch them all here and then pass them off to the agregate method
 		// instead of creating methods for each one of them.
 		if (in_array($method, array('count', 'min', 'max', 'avg', 'sum')))
 		{

+ 1 - 1
laravel/database/schema/grammars/mysql.php

@@ -383,7 +383,7 @@ class MySQL extends Grammar {
 	 */
 	protected function type_boolean(Fluent $column)
 	{
-		return 'TINYINT';
+		return 'TINYINT(1)';
 	}
 
 	/**

+ 11 - 0
laravel/documentation/changes.md

@@ -2,6 +2,8 @@
 
 ## Contents
 
+- [Laravel 3.2.5](#3.2.5)
+- [Upgrading From 3.2.4](#upgrade-3.2.5)
 - [Laravel 3.2.4](#3.2.4)
 - [Upgrading From 3.2.3](#upgrade-3.2.4)
 - [Laravel 3.2.3](#3.2.3)
@@ -33,6 +35,15 @@
 - [Laravel 3.1](#3.1)
 - [Upgrading From 3.0](#upgrade-3.1)
 
+<a name="3.2.5"></a>
+
+- Revert nested where code back to 3.2.3 tag.
+
+<a name="upgrade-3.2.5"></a>
+## Upgrading From 3.2.4
+
+- Replace the **laravel** folder.
+
 <a name="3.2.4"></a>
 ## Laravel 3.2.4
 

+ 19 - 19
laravel/profiling/profiler.js

@@ -6,20 +6,20 @@ var anbu = {
 	// the DOM every time they are used.
 
 	el: {
-		main: $('.anbu'),
-		close: $('#anbu-close'),
-		zoom: $('#anbu-zoom'),
-		hide: $('#anbu-hide'),
-		show: $('#anbu-show'),
-		tab_pane: $('.anbu-tab-pane'),
-		hidden_tab_pane: $('.anbu-tab-pane:visible'),
-		tab: $('.anbu-tab'),
-		tabs: $('.anbu-tabs'),
-		tab_links: $('.anbu-tabs a'),
-		window: $('.anbu-window'),
-		closed_tabs: $('#anbu-closed-tabs'),
-		open_tabs: $('#anbu-open-tabs'),
-		content_area: $('.anbu-content-area')
+		main: jQuery('.anbu'),
+		close: jQuery('#anbu-close'),
+		zoom: jQuery('#anbu-zoom'),
+		hide: jQuery('#anbu-hide'),
+		show: jQuery('#anbu-show'),
+		tab_pane: jQuery('.anbu-tab-pane'),
+		hidden_tab_pane: jQuery('.anbu-tab-pane:visible'),
+		tab: jQuery('.anbu-tab'),
+		tabs: jQuery('.anbu-tabs'),
+		tab_links: jQuery('.anbu-tabs a'),
+		window: jQuery('.anbu-window'),
+		closed_tabs: jQuery('#anbu-closed-tabs'),
+		open_tabs: jQuery('#anbu-open-tabs'),
+		content_area: jQuery('.anbu-content-area')
 	},
 
 	// CLASS ATTRIBUTES
@@ -30,7 +30,7 @@ var anbu = {
 	is_zoomed: false,
 
 	// initial height of content area
-	small_height: $('.anbu-content-area').height(),
+	small_height: jQuery('.anbu-content-area').height(),
 
 	// the name of the active tab css
 	active_tab: 'anbu-active-tab',
@@ -76,7 +76,7 @@ var anbu = {
 			event.preventDefault();
 		});
 		anbu.el.tab.click(function(event) {
-			anbu.clicked_tab($(this));
+			anbu.clicked_tab(jQuery(this));
 			event.preventDefault();
 		});
 
@@ -104,8 +104,8 @@ var anbu = {
 	open_window: function(tab) {
 
 		// can't directly assign this line, but it works
-		$('.anbu-tab-pane:visible').fadeOut(200);
-		$('.' + tab.attr(anbu.tab_data)).delay(220).fadeIn(300);
+		jQuery('.anbu-tab-pane:visible').fadeOut(200);
+		jQuery('.' + tab.attr(anbu.tab_data)).delay(220).fadeIn(300);
 		anbu.el.tab_links.removeClass(anbu.active_tab);
 		tab.addClass(anbu.active_tab);
 		anbu.el.window.slideDown(300);
@@ -178,7 +178,7 @@ var anbu = {
 			anbu.is_zoomed = false;
 		} else {
 			// the 6px is padding on the top of the window
-			height = ($(window).height() - anbu.el.tabs.height() - 6) + 'px';
+			height = (jQuery(window).height() - anbu.el.tabs.height() - 6) + 'px';
 			anbu.is_zoomed = true;
 		}
 

+ 19 - 0
laravel/redirect.php

@@ -165,4 +165,23 @@ class Redirect extends Response {
 		return $this->with('errors', $errors);
 	}
 
+	/**
+	 * Send the headers and content of the response to the browser.
+	 *
+	 * @return void
+	 */
+	public function send()
+	{
+		// Dump all output buffering, this ensures
+		// that symphony will send our redirect headers
+		// properly if we've outputted any content from
+		// within Laravel.
+		while (ob_get_level() > 0)
+		{
+			ob_end_clean();
+		}
+
+		return parent::send();
+	}
+
 }

+ 2 - 0
laravel/routing/controller.php

@@ -179,6 +179,8 @@ abstract class Controller {
 		// controllers with much less code than would be usual.
 		foreach ($parameters as $key => $value)
 		{
+			if ( ! is_string($value)) continue;
+
 			$search = '(:'.($key + 1).')';
 
 			$destination = str_replace($search, $value, $destination, $count);

+ 36 - 0
laravel/tests/application/bundles.php

@@ -0,0 +1,36 @@
+<?php
+
+/*
+|--------------------------------------------------------------------------
+| Bundle Configuration
+|--------------------------------------------------------------------------
+|
+| Bundles allow you to conveniently extend and organize your application.
+| Think of bundles as self-contained applications. They can have routes,
+| controllers, models, views, configuration, etc. You can even create
+| your own bundles to share with the Laravel community.
+|
+| This is a list of the bundles installed for your application and tells
+| Laravel the location of the bundle's root directory, as well as the
+| root URI the bundle responds to.
+|
+| For example, if you have an "admin" bundle located in "bundles/admin" 
+| that you want to handle requests with URIs that begin with "admin",
+| simply add it to the array like this:
+|
+|		'admin' => array(
+|			'location' => 'admin',
+|			'handles'  => 'admin',
+|		),
+|
+| Note that the "location" is relative to the "bundles" directory.
+| Now the bundle will be recognized by Laravel and will be able
+| to respond to requests beginning with "admin"!
+|
+| Have a bundle that lives in the root of the bundle directory
+| and doesn't respond to any requests? Just add the bundle
+| name to the array and we'll take care of the rest.
+|
+*/
+
+return array('dashboard' => array('handles' => 'dashboard'), 'dummy');

+ 158 - 0
laravel/tests/application/config/application.php

@@ -0,0 +1,158 @@
+<?php
+
+return array(
+
+	/*
+	|--------------------------------------------------------------------------
+	| Application URL
+	|--------------------------------------------------------------------------
+	|
+	| The URL used to access your application without a trailing slash. The URL
+	| does nto have to be set. If it isn't we'll try our best to guess the URL
+	| of your application.
+	|
+	*/
+
+	'url' => '',
+
+	/*
+	|--------------------------------------------------------------------------
+	| Application Index
+	|--------------------------------------------------------------------------
+	|
+	| If you are including the "index.php" in your URLs, you can ignore this.
+	|
+	| However, if you are using mod_rewrite to get cleaner URLs, just set
+	| this option to an empty string and we'll take care of the rest.
+	|
+	*/
+
+	'index' => 'index.php',
+
+	/*
+	|--------------------------------------------------------------------------
+	| Application Key
+	|--------------------------------------------------------------------------
+	|
+	| This key is used by the encryption and cookie classes to generate secure
+	| encrypted strings and hashes. It is extremely important that this key
+	| remain secret and should not be shared with anyone. Make it about 32
+	| characters of random gibberish.
+	|
+	*/
+
+	'key' => '',
+
+	/*
+	|--------------------------------------------------------------------------
+	| Application Character Encoding
+	|--------------------------------------------------------------------------
+	|
+	| The default character encoding used by your application. This encoding
+	| will be used by the Str, Text, Form, and any other classes that need
+	| to know what type of encoding to use for your awesome application.
+	|
+	*/
+
+	'encoding' => 'UTF-8',
+
+	/*
+	|--------------------------------------------------------------------------
+	| Application Language
+	|--------------------------------------------------------------------------
+	|
+	| The default language of your application. This language will be used by
+	| Lang library as the default language when doing string localization.
+	|
+	*/
+
+	'language' => 'en',
+
+	/*
+	|--------------------------------------------------------------------------
+	| SSL Link Generation
+	|--------------------------------------------------------------------------
+	|
+	| Many sites use SSL to protect their users data. However, you may not
+	| always be able to use SSL on your development machine, meaning all HTTPS
+	| will be broken during development.
+	|
+	| For this reason, you may wish to disable the generation of HTTPS links
+	| throughout your application. This option does just that. All attempts to
+	| generate HTTPS links will generate regular HTTP links instead.
+	|
+	*/
+
+	'ssl' => true,
+
+	/*
+	|--------------------------------------------------------------------------
+	| Application Timezone
+	|--------------------------------------------------------------------------
+	|
+	| The default timezone of your application. This timezone will be used when
+	| Laravel needs a date, such as when writing to a log file or travelling
+	| to a distant star at warp speed.
+	|
+	*/
+
+	'timezone' => 'UTC',
+
+	/*
+	|--------------------------------------------------------------------------
+	| Class Aliases
+	|--------------------------------------------------------------------------
+	|
+	| Here, you can specify any class aliases that you would like registered
+	| when Laravel loads. Aliases are lazy-loaded, so add as many as you want.
+	|
+	| Aliases make it more convenient to use namespaced classes. Instead of
+	| referring to the class using its full namespace, you may simply use
+	| the alias defined here.
+	|
+	| We have already aliased common Laravel classes to make your life easier.
+	|
+	*/
+
+	'aliases' => array(
+		'Auth'       => 'Laravel\\Auth',
+		'Asset'      => 'Laravel\\Asset',
+		'Autoloader' => 'Laravel\\Autoloader',
+		'Blade'      => 'Laravel\\Blade',
+		'Bundle'     => 'Laravel\\Bundle',
+		'Cache'      => 'Laravel\\Cache',
+		'Config'     => 'Laravel\\Config',
+		'Controller' => 'Laravel\\Routing\\Controller',
+		'Cookie'     => 'Laravel\\Cookie',
+		'Crypter'    => 'Laravel\\Crypter',
+		'DB'         => 'Laravel\\Database',
+		'Event'      => 'Laravel\\Event',
+		'File'       => 'Laravel\\File',
+		'Filter'     => 'Laravel\\Routing\\Filter',
+		'Form'       => 'Laravel\\Form',
+		'Hash'       => 'Laravel\\Hash',
+		'HTML'       => 'Laravel\\HTML',
+		'Input'      => 'Laravel\\Input',
+		'IoC'        => 'Laravel\\IoC',
+		'Lang'       => 'Laravel\\Lang',
+		'Log'        => 'Laravel\\Log',
+		'Memcached'  => 'Laravel\\Memcached',
+		'Paginator'  => 'Laravel\\Paginator',
+		'URL'        => 'Laravel\\URL',
+		'Redirect'   => 'Laravel\\Redirect',
+		'Redis'      => 'Laravel\\Redis',
+		'Request'    => 'Laravel\\Request',
+		'Response'   => 'Laravel\\Response',
+		'Route'      => 'Laravel\\Routing\\Route',
+		'Router'     => 'Laravel\\Routing\\Router',
+		'Schema'     => 'Laravel\\Database\\Schema',
+		'Section'    => 'Laravel\\Section',
+		'Session'    => 'Laravel\\Session',
+		'Str'        => 'Laravel\\Str',
+		'Task'       => 'Laravel\\CLI\\Tasks\\Task',
+		'URI'        => 'Laravel\\URI',
+		'Validator'  => 'Laravel\\Validator',
+		'View'       => 'Laravel\\View',
+	),
+
+);

+ 73 - 0
laravel/tests/application/config/auth.php

@@ -0,0 +1,73 @@
+<?php
+
+return array(
+
+	/*
+	|--------------------------------------------------------------------------
+	| Default Authentication Driver
+	|--------------------------------------------------------------------------
+	|
+	| Laravel uses a flexible driver-based system to handle authentication.
+	| You are free to register your own drivers using the Auth::extend
+	| method. Of course, a few great drivers are provided out of
+	| box to handle basic authentication simply and easily.
+	|
+	| Drivers: 'fluent', 'eloquent'.
+	|
+	*/
+
+	'driver' => 'fluent',
+
+	/*
+	|--------------------------------------------------------------------------
+	| Authentication Username
+	|--------------------------------------------------------------------------
+	|
+	| Here you may specify the database column that should be considered the
+	| "username" for your users. Typically, this will either be "username"
+	| or "email". Of course, you're free to change the value to anything.
+	|
+	*/
+
+	'username' => 'username',
+
+	/*
+	|--------------------------------------------------------------------------
+	| Authentication Password
+	|--------------------------------------------------------------------------
+	|
+	| Here you may specify the database column that should be considered the
+	| "password" for your users. Typically, this will be "password" but,
+	| again, you're free to change the value to anything you see fit.
+	|
+	*/
+
+	'password' => 'password',
+
+	/*
+	|--------------------------------------------------------------------------
+	| Authentication Model
+	|--------------------------------------------------------------------------
+	|
+	| When using the "eloquent" authentication driver, you may specify the
+	| model that should be considered the "User" model. This model will
+	| be used to authenticate and load the users of your application.
+	|
+	*/
+
+	'model' => 'User',
+
+	/*
+	|--------------------------------------------------------------------------
+	| Authentication Table
+	|--------------------------------------------------------------------------
+	|
+	| When using the "fluent" authentication driver, the database table used
+	| to load users may be specified here. This table will be used in by
+	| the fluent query builder to authenticate and load your users.
+	|
+	*/
+
+	'table' => 'users',
+
+);

+ 71 - 0
laravel/tests/application/config/cache.php

@@ -0,0 +1,71 @@
+<?php
+
+return array(
+
+	/*
+	|--------------------------------------------------------------------------
+	| Cache Driver
+	|--------------------------------------------------------------------------
+	|
+	| The name of the default cache driver for your application. Caching can
+	| be used to increase the performance of your application by storing any
+	| commonly accessed data in memory, a file, or some other storage.
+	|
+	| A variety of awesome drivers are available for you to use with Laravel.
+	| Some, like APC, are extremely fast. However, if that isn't an option
+	| in your environment, try file or database caching.
+	|
+	| Drivers: 'file', 'memcached', 'apc', 'redis', 'database'.
+	|
+	*/
+
+	'driver' => 'file',
+
+	/*
+	|--------------------------------------------------------------------------
+	| Cache Key
+	|--------------------------------------------------------------------------
+	|
+	| This key will be prepended to item keys stored using Memcached and APC
+	| to prevent collisions with other applications on the server. Since the
+	| memory based stores could be shared by other applications, we need to
+	| be polite and use a prefix to uniquely identifier our items.
+	|
+	*/
+
+	'key' => 'laravel',
+
+	/*
+	|--------------------------------------------------------------------------
+	| Cache Database
+	|--------------------------------------------------------------------------
+	|
+	| When using the database cache driver, this database table will be used
+	| to store the cached item. You may also add a "connection" option to
+	| the array to specify which database connection should be used.
+	|
+	*/
+
+	'database' => array('table' => 'laravel_cache'),
+
+	/*
+	|--------------------------------------------------------------------------
+	| Memcached Servers
+	|--------------------------------------------------------------------------
+	|
+	| The Memcached servers used by your application. Memcached is a free and
+	| open source, high-performance, distributed memory caching system. It is
+	| generic in nature but intended for use in speeding up web applications
+	| by alleviating database load.
+	|
+	| For more information, check out: http://memcached.org
+	|
+	*/
+
+	'memcached' => array(
+
+		array('host' => '127.0.0.1', 'port' => 11211, 'weight' => 100),
+
+	),	
+
+);

+ 108 - 0
laravel/tests/application/config/database.php

@@ -0,0 +1,108 @@
+<?php
+
+return array(
+
+	/*
+	|--------------------------------------------------------------------------
+	| Default Database Connection
+	|--------------------------------------------------------------------------
+	|
+	| The name of your default database connection. This connection will used
+	| as the default for all database operations unless a different name is
+	| given when performing said operation. This connection name should be
+	| listed in the array of connections below.
+	|
+	*/
+
+	'default' => 'sqlite',
+
+	/*
+	|--------------------------------------------------------------------------
+	| PDO Fetch Style
+	|--------------------------------------------------------------------------
+	|
+	| By default, database results will be returned as instances of the PHP
+	| stdClass object; however, you may wish to retrieve records as arrays
+	| instead of objects. Here you can control the PDO fetch style of the
+	| database queries run by your application.
+	|
+	*/
+
+	'fetch' => PDO::FETCH_CLASS,
+
+	/*
+	|--------------------------------------------------------------------------
+	| Database Connections
+	|--------------------------------------------------------------------------
+	|
+	| All of the database connections used by your application. Many of your
+	| applications will no doubt only use one connection; however, you have
+	| the freedom to specify as many connections as you can handle.
+	|
+	| All database work in Laravel is done through the PHP's PDO facilities,
+	| so make sure you have the PDO drivers for your particlar database of
+	| choice installed on your machine.
+	|
+	| Drivers: 'mysql', 'pgsql', 'sqlsrv', 'sqlite'.
+	|
+	*/
+
+	'connections' => array(
+
+		'sqlite' => array(
+			'driver'   => 'sqlite',
+			'database' => 'application',
+			'prefix'   => '',
+		),
+
+		'mysql' => array(
+			'driver'   => 'mysql',
+			'host'     => 'localhost',
+			'database' => 'database',
+			'username' => 'root',
+			'password' => 'password',
+			'charset'  => 'utf8',
+			'prefix'   => '',
+		),
+
+		'pgsql' => array(
+			'driver'   => 'pgsql',
+			'host'     => 'localhost',
+			'database' => 'database',
+			'username' => 'root',
+			'password' => 'password',
+			'charset'  => 'utf8',
+			'prefix'   => '',
+		),
+
+		'sqlsrv' => array(
+			'driver'   => 'sqlsrv',
+			'host'     => 'localhost',
+			'database' => 'database',
+			'username' => 'root',
+			'password' => 'password',
+			'prefix'   => '',
+		),
+
+	),
+
+	/*
+	|--------------------------------------------------------------------------
+	| Redis Databases
+	|--------------------------------------------------------------------------
+	|
+	| Redis is an open source, fast, and advanced key-value store. However, it
+	| provides a richer set of commands than a typical key-value store such as
+	| APC or memcached. All the cool kids are using it.
+	|
+	| To get the scoop on Redis, check out: http://redis.io
+	|
+	*/
+
+	'redis' => array(
+
+		'default' => array('host' => '127.0.0.1', 'port' => 6379),
+
+	),
+
+);

+ 69 - 0
laravel/tests/application/config/error.php

@@ -0,0 +1,69 @@
+<?php
+
+return array(
+
+	/*
+	|--------------------------------------------------------------------------
+	| Ignored Error Levels
+	|--------------------------------------------------------------------------
+	|
+	| Here you simply specify the error levels that should be ignored by the
+	| Laravel error handler. These levels will still be logged; however, no
+	| information about about them will be displayed.
+	|
+	*/
+
+	'ignore' => array(E_NOTICE, E_USER_NOTICE, E_DEPRECATED, E_USER_DEPRECATED),
+
+	/*
+	|--------------------------------------------------------------------------
+	| Error Detail
+	|--------------------------------------------------------------------------
+	|
+	| Detailed error messages contain information about the file in which an
+	| error occurs, as well as a PHP stack trace containing the call stack.
+	| You'll want them when you're trying to debug your application.
+	|
+	| If your application is in production, you'll want to turn off the error
+	| details for enhanced security and user experience since the exception
+	| stack trace could contain sensitive information.
+	|
+	*/
+
+	'detail' => true,
+
+	/*
+	|--------------------------------------------------------------------------
+	| Error Logging
+	|--------------------------------------------------------------------------
+	|
+	| When error logging is enabled, the "logger" Closure defined below will
+	| be called for every error in your application. You are free to log the
+	| errors however you want. Enjoy the flexibility.
+	|
+	*/
+
+	'log' => false,
+
+	/*
+	|--------------------------------------------------------------------------
+	| Error Logger
+	|--------------------------------------------------------------------------
+	|
+	| Because of the various ways of managing error logging, you get complete
+	| flexibility to manage error logging as you see fit. This function will
+	| be called anytime an error occurs within your application and error
+	| logging is enabled. 
+	|
+	| You may log the error message however you like; however, a simple log
+	| solution has been setup for you which will log all error messages to
+	| text files within the application storage directory.
+	|
+	*/
+
+	'logger' => function($exception)
+	{
+		Log::exception($exception);
+	},
+
+);

+ 7 - 0
laravel/tests/application/config/local/database.php

@@ -0,0 +1,7 @@
+<?php
+
+return array(
+
+	'default' => 'sqlite',
+
+);

+ 97 - 0
laravel/tests/application/config/mimes.php

@@ -0,0 +1,97 @@
+<?php
+
+return array(
+
+	'hqx'   => 'application/mac-binhex40',
+	'cpt'   => 'application/mac-compactpro',
+	'csv'   => array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream'),
+	'bin'   => 'application/macbinary',
+	'dms'   => 'application/octet-stream',
+	'lha'   => 'application/octet-stream',
+	'lzh'   => 'application/octet-stream',
+	'exe'   => array('application/octet-stream', 'application/x-msdownload'),
+	'class' => 'application/octet-stream',
+	'psd'   => 'application/x-photoshop',
+	'so'    => 'application/octet-stream',
+	'sea'   => 'application/octet-stream',
+	'dll'   => 'application/octet-stream',
+	'oda'   => 'application/oda',
+	'pdf'   => array('application/pdf', 'application/x-download'),
+	'ai'    => 'application/postscript',
+	'eps'   => 'application/postscript',
+	'ps'    => 'application/postscript',
+	'smi'   => 'application/smil',
+	'smil'  => 'application/smil',
+	'mif'   => 'application/vnd.mif',
+	'xls'   => array('application/excel', 'application/vnd.ms-excel', 'application/msexcel'),
+	'ppt'   => array('application/powerpoint', 'application/vnd.ms-powerpoint'),
+	'wbxml' => 'application/wbxml',
+	'wmlc'  => 'application/wmlc',
+	'dcr'   => 'application/x-director',
+	'dir'   => 'application/x-director',
+	'dxr'   => 'application/x-director',
+	'dvi'   => 'application/x-dvi',
+	'gtar'  => 'application/x-gtar',
+	'gz'    => 'application/x-gzip',
+	'php'   => array('application/x-httpd-php', 'text/x-php'),
+	'php4'  => 'application/x-httpd-php',
+	'php3'  => 'application/x-httpd-php',
+	'phtml' => 'application/x-httpd-php',
+	'phps'  => 'application/x-httpd-php-source',
+	'js'    => 'application/x-javascript',
+	'swf'   => 'application/x-shockwave-flash',
+	'sit'   => 'application/x-stuffit',
+	'tar'   => 'application/x-tar',
+	'tgz'   => array('application/x-tar', 'application/x-gzip-compressed'),
+	'xhtml' => 'application/xhtml+xml',
+	'xht'   => 'application/xhtml+xml',
+	'zip'   => array('application/x-zip', 'application/zip', 'application/x-zip-compressed'),
+	'mid'   => 'audio/midi',
+	'midi'  => 'audio/midi',
+	'mpga'  => 'audio/mpeg',
+	'mp2'   => 'audio/mpeg',
+	'mp3'   => array('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'),
+	'aif'   => 'audio/x-aiff',
+	'aiff'  => 'audio/x-aiff',
+	'aifc'  => 'audio/x-aiff',
+	'ram'   => 'audio/x-pn-realaudio',
+	'rm'    => 'audio/x-pn-realaudio',
+	'rpm'   => 'audio/x-pn-realaudio-plugin',
+	'ra'    => 'audio/x-realaudio',
+	'rv'    => 'video/vnd.rn-realvideo',
+	'wav'   => 'audio/x-wav',
+	'bmp'   => 'image/bmp',
+	'gif'   => 'image/gif',
+	'jpeg'  => array('image/jpeg', 'image/pjpeg'),
+	'jpg'   => array('image/jpeg', 'image/pjpeg'),
+	'jpe'   => array('image/jpeg', 'image/pjpeg'),
+	'png'   => 'image/png',
+	'tiff'  => 'image/tiff',
+	'tif'   => 'image/tiff',
+	'css'   => 'text/css',
+	'html'  => 'text/html',
+	'htm'   => 'text/html',
+	'shtml' => 'text/html',
+	'txt'   => 'text/plain',
+	'text'  => 'text/plain',
+	'log'   => array('text/plain', 'text/x-log'),
+	'rtx'   => 'text/richtext',
+	'rtf'   => 'text/rtf',
+	'xml'   => 'text/xml',
+	'xsl'   => 'text/xml',
+	'mpeg'  => 'video/mpeg',
+	'mpg'   => 'video/mpeg',
+	'mpe'   => 'video/mpeg',
+	'qt'    => 'video/quicktime',
+	'mov'   => 'video/quicktime',
+	'avi'   => 'video/x-msvideo',
+	'movie' => 'video/x-sgi-movie',
+	'doc'   => 'application/msword',
+	'docx'  => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+	'xlsx'  => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+	'word'  => array('application/msword', 'application/octet-stream'),
+	'xl'    => 'application/excel',
+	'eml'   => 'message/rfc822',
+	'json'  => array('application/json', 'text/json'),
+
+);

+ 117 - 0
laravel/tests/application/config/session.php

@@ -0,0 +1,117 @@
+<?php
+
+return array(
+
+	/*
+	|--------------------------------------------------------------------------
+	| Session Driver
+	|--------------------------------------------------------------------------
+	|
+	| The name of the session driver used by your application. Since HTTP is
+	| stateless, sessions are used to simulate "state" across requests made
+	| by the same user of your application. In other words, it's how an
+	| application knows who the heck you are.
+	|
+	| Drivers: 'cookie', 'file', 'database', 'memcached', 'apc', 'redis'.
+	|
+	*/
+
+	'driver' => '',
+
+	/*
+	|--------------------------------------------------------------------------
+	| Session Database
+	|--------------------------------------------------------------------------
+	|
+	| The database table on which the session should be stored. It probably
+	| goes without saying that this option only matters if you are using
+	| the super slick database session driver.
+	|
+	*/
+
+	'table' => 'sessions',
+
+	/*
+	|--------------------------------------------------------------------------
+	| Session Garbage Collection Probability
+	|--------------------------------------------------------------------------
+	|
+	| Some session drivers require the manual clean-up of expired sessions.
+	| This option specifies the probability of session garbage collection
+	| occuring for any given request. 
+	|
+	| For example, the default value states that garbage collection has a
+	| 2% chance of occuring for any given request to the application.
+	| Feel free to tune this to your application's size and speed.
+	|
+	*/
+
+	'sweepage' => array(2, 100),
+
+	/*
+	|--------------------------------------------------------------------------
+	| Session Lifetime
+	|--------------------------------------------------------------------------
+	|
+	| The number of minutes a session can be idle before expiring.
+	|
+	*/
+
+	'lifetime' => 60,
+
+	/*
+	|--------------------------------------------------------------------------
+	| Session Expiration On Close
+	|--------------------------------------------------------------------------
+	|
+	| Determines if the session should expire when the user's web browser closes.
+	|
+	*/
+
+	'expire_on_close' => false,
+
+	/*
+	|--------------------------------------------------------------------------
+	| Session Cookie Name
+	|--------------------------------------------------------------------------
+	|
+	| The name that should be given to the session cookie.
+	|
+	*/
+
+	'cookie' => 'laravel_session',
+
+	/*
+	|--------------------------------------------------------------------------
+	| Session Cookie Path
+	|--------------------------------------------------------------------------
+	|
+	| The path for which the session cookie is available.
+	|
+	*/
+
+	'path' => '/',
+
+	/*
+	|--------------------------------------------------------------------------
+	| Session Cookie Domain
+	|--------------------------------------------------------------------------
+	|
+	| The domain for which the session cookie is available.
+	|
+	*/
+
+	'domain' => null,
+
+	/*
+	|--------------------------------------------------------------------------
+	| HTTPS Only Session Cookie
+	|--------------------------------------------------------------------------
+	|
+	| Determines if the cookie should only be sent over HTTPS.
+	|
+	*/
+
+	'secure' => false,
+
+);

+ 187 - 0
laravel/tests/application/config/strings.php

@@ -0,0 +1,187 @@
+<?php
+
+return array(
+
+	/*
+	|--------------------------------------------------------------------------
+	| String Inflection
+	|--------------------------------------------------------------------------
+	|
+	| This array contains the singular and plural forms of words. It's used by
+	| the "singular" and "plural" methods on the Str class to convert a given
+	| word from singular to plural and vice versa.
+	|
+	| Note that the regular expressions are only for inflecting English words.
+	| To inflect a non-English string, simply add its singular and plural
+	| form to the array of "irregular" word forms.
+	|
+	*/
+
+	'plural' => array(
+		'/(quiz)$/i' => "$1zes",
+		'/^(ox)$/i' => "$1en",
+		'/([m|l])ouse$/i' => "$1ice",
+		'/(matr|vert|ind)ix|ex$/i' => "$1ices",
+		'/(x|ch|ss|sh)$/i' => "$1es",
+		'/([^aeiouy]|qu)y$/i' => "$1ies",
+		'/(hive)$/i' => "$1s",
+		'/(?:([^f])fe|([lr])f)$/i' => "$1$2ves",
+		'/(shea|lea|loa|thie)f$/i' => "$1ves",
+		'/sis$/i' => "ses",
+		'/([ti])um$/i' => "$1a",
+		'/(tomat|potat|ech|her|vet)o$/i' => "$1oes",
+		'/(bu)s$/i' => "$1ses",
+		'/(alias)$/i' => "$1es",
+		'/(octop)us$/i' => "$1i",
+		'/(ax|test)is$/i' => "$1es",
+		'/(us)$/i' => "$1es",
+		'/s$/i' => "s",
+		'/$/' => "s"
+	),
+
+	'singular' => array(
+		'/(quiz)zes$/i' => "$1",
+		'/(matr)ices$/i' => "$1ix",
+		'/(vert|ind)ices$/i' => "$1ex",
+		'/^(ox)en$/i' => "$1",
+		'/(alias)es$/i' => "$1",
+		'/(octop|vir)i$/i' => "$1us",
+		'/(cris|ax|test)es$/i' => "$1is",
+		'/(shoe)s$/i' => "$1",
+		'/(o)es$/i' => "$1",
+		'/(bus)es$/i' => "$1",
+		'/([m|l])ice$/i' => "$1ouse",
+		'/(x|ch|ss|sh)es$/i' => "$1",
+		'/(m)ovies$/i' => "$1ovie",
+		'/(s)eries$/i' => "$1eries",
+		'/([^aeiouy]|qu)ies$/i' => "$1y",
+		'/([lr])ves$/i' => "$1f",
+		'/(tive)s$/i' => "$1",
+		'/(hive)s$/i' => "$1",
+		'/(li|wi|kni)ves$/i' => "$1fe",
+		'/(shea|loa|lea|thie)ves$/i' => "$1f",
+		'/(^analy)ses$/i' => "$1sis",
+		'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => "$1$2sis",
+		'/([ti])a$/i' => "$1um",
+		'/(n)ews$/i' => "$1ews",
+		'/(h|bl)ouses$/i' => "$1ouse",
+		'/(corpse)s$/i' => "$1",
+		'/(us)es$/i' => "$1",
+		'/(us|ss)$/i' => "$1",
+		'/s$/i' => "",
+	),
+
+	'irregular' => array(
+		'child' => 'children',
+		'foot' => 'feet',
+		'goose' => 'geese',
+		'man' => 'men',
+		'move' => 'moves',
+		'person' => 'people',
+		'sex' => 'sexes',
+		'tooth' => 'teeth',
+	),
+
+	'uncountable' => array(
+		'audio',
+		'equipment',
+		'deer',
+		'fish',
+		'gold',
+		'information',
+		'money',
+		'rice',
+		'police',
+		'series',
+		'sheep',
+		'species',
+	),
+
+	/*
+	|--------------------------------------------------------------------------
+	| ASCII Characters
+	|--------------------------------------------------------------------------
+	|
+	| This array contains foreign characters and their 7-bit ASCII equivalents.
+	| The array is used by the "ascii" method on the Str class to get strings
+	| ready for inclusion in a URL slug.
+	|
+	| Of course, the "ascii" method may also be used by you for whatever your
+	| application requires. Feel free to add any characters we missed, and be
+	| sure to let us know about them!
+	|
+	*/
+
+	'ascii' => array(
+
+		'/รฆ|วฝ/' => 'ae',
+		'/ล“/' => 'oe',
+		'/ร€|ร|ร‚|รƒ|ร„|ร…|วบ|ฤ€|ฤ‚|ฤ„|ว|ะ/' => 'A',
+		'/ร |รก|รข|รฃ|รค|รฅ|วป|ฤ|ฤƒ|ฤ…|วŽ|ยช|ะฐ/' => 'a',
+		'/ะ‘/' => 'B',
+		'/ะฑ/' => 'b',
+		'/ร‡|ฤ†|ฤˆ|ฤŠ|ฤŒ|ะฆ/' => 'C',
+		'/รง|ฤ‡|ฤ‰|ฤ‹|ฤ|ั†/' => 'c',
+		'/ร|ฤŽ|ฤ|ะ”/' => 'Dj',
+		'/รฐ|ฤ|ฤ‘|ะด/' => 'dj',
+		'/รˆ|ร‰|รŠ|ร‹|ฤ’|ฤ”|ฤ–|ฤ˜|ฤš|ะ•|ะ|ะญ/' => 'E',
+		'/รจ|รฉ|รช|รซ|ฤ“|ฤ•|ฤ—|ฤ™|ฤ›|ะต|ั‘|ั/' => 'e',
+		'/ะค/' => 'F',
+		'/ฦ’|ั„/' => 'f',
+		'/ฤœ|ฤž|ฤ |ฤข|ะ“/' => 'G',
+		'/ฤ|ฤŸ|ฤก|ฤฃ|ะณ/' => 'g',
+		'/ฤค|ฤฆ|ะฅ/' => 'H',
+		'/ฤฅ|ฤง|ั…/' => 'h',
+		'/รŒ|ร|รŽ|ร|ฤจ|ฤช|ฤฌ|ว|ฤฎ|ฤฐ|ะ˜/' => 'I',
+		'/รฌ|รญ|รฎ|รฏ|ฤฉ|ฤซ|ฤญ|ว|ฤฏ|ฤฑ|ะธ/' => 'i',
+		'/ฤด|ะ™/' => 'J',
+		'/ฤต|ะน/' => 'j',
+		'/ฤถ|ะš/' => 'K',
+		'/ฤท|ะบ/' => 'k',
+		'/ฤน|ฤป|ฤฝ|ฤฟ|ล|ะ›/' => 'L',
+		'/ฤบ|ฤผ|ฤพ|ล€|ล‚|ะป/' => 'l',
+		'/ะœ/' => 'M',
+		'/ะผ/' => 'm',
+		'/ร‘|ลƒ|ล…|ล‡|ะ/' => 'N',
+		'/รฑ|ล„|ล†|ลˆ|ล‰|ะฝ/' => 'n',
+		'/ร–|ร’|ร“|ร”|ร•|ลŒ|ลŽ|ว‘|ล|ฦ |ร˜|วพ|ะž/' => 'O',
+		'/รถ|รฒ|รณ|รด|รต|ล|ล|ว’|ล‘|ฦก|รธ|วฟ|ยบ|ะพ/' => 'o',
+		'/ะŸ/' => 'P',
+		'/ะฟ/' => 'p',
+		'/ล”|ล–|ล˜|ะ /' => 'R',
+		'/ล•|ล—|ล™|ั€/' => 'r',
+		'/ลš|ลœ|ลž|ศ˜|ล |ะก/' => 'S',
+		'/ล›|ล|ลŸ|ศ™|ลก|ลฟ|ั/' => 's',
+		'/ลข|ศš|ลค|ลฆ|ะข/' => 'T',
+		'/ลฃ|ศ›|ลฅ|ลง|ั‚/' => 't',
+		'/ร™|รš|ร›|ลจ|ลช|ลฌ|ลฎ|รœ|ลฐ|ลฒ|ฦฏ|ว“|ว•|ว—|ว™|ว›|ะฃ/' => 'U',
+		'/รน|รบ|รป|ลฉ|ลซ|ลญ|ลฏ|รผ|ลฑ|ลณ|ฦฐ|ว”|ว–|ว˜|วš|วœ|ัƒ/' => 'u',
+		'/ะ’/' => 'V',
+		'/ะฒ/' => 'v',
+		'/ร|ลธ|ลถ|ะซ/' => 'Y',
+		'/รฝ|รฟ|ลท|ั‹/' => 'y',
+		'/ลด/' => 'W',
+		'/ลต/' => 'w',
+		'/ลน|ลป|ลฝ|ะ—/' => 'Z',
+		'/ลบ|ลผ|ลพ|ะท/' => 'z',
+		'/ร†|วผ/' => 'AE',
+		'/รŸ/'=> 'ss',
+		'/ฤฒ/' => 'IJ',
+		'/ฤณ/' => 'ij',
+		'/ล’/' => 'OE',
+		'/ะง/' => 'Ch',
+		'/ั‡/' => 'ch',
+		'/ะฎ/' => 'Ju',
+		'/ัŽ/' => 'ju',
+		'/ะฏ/' => 'Ja',
+		'/ั/' => 'ja',
+		'/ะจ/' => 'Sh',
+		'/ัˆ/' => 'sh',
+		'/ะฉ/' => 'Shch',
+		'/ั‰/' => 'shch',
+		'/ะ–/' => 'Zh',
+		'/ะถ/' => 'zh',
+
+	),
+
+);

+ 10 - 0
laravel/tests/application/controllers/admin/panel.php

@@ -0,0 +1,10 @@
+<?php
+
+class Admin_Panel_Controller extends Controller {
+
+	public function action_index()
+	{
+		return 'Admin_Panel_Index';
+	}
+
+}

+ 20 - 0
laravel/tests/application/controllers/auth.php

@@ -0,0 +1,20 @@
+<?php
+
+class Auth_Controller extends Controller {
+
+	public function action_index()
+	{
+		return __FUNCTION__;
+	}
+
+	public function action_login()
+	{
+		return __FUNCTION__;
+	}
+
+	public function action_profile($name)
+	{
+		return $name;
+	}
+
+}

+ 65 - 0
laravel/tests/application/controllers/filter.php

@@ -0,0 +1,65 @@
+<?php
+
+class Filter_Controller extends Controller {
+
+	public function __construct()
+	{
+		Filter::register('test-all-before', function() { $_SERVER['test-all-before'] = true; });
+		Filter::register('test-all-after', function() { $_SERVER['test-all-after'] = true; });
+		Filter::register('test-profile-before', function() { $_SERVER['test-profile-before'] = true; });
+		Filter::register('test-except', function() { $_SERVER['test-except'] = true; });
+		Filter::register('test-on-post', function() { $_SERVER['test-on-post'] = true; });
+		Filter::register('test-on-get-put', function() { $_SERVER['test-on-get-put'] = true; });
+		Filter::register('test-before-filter', function() { return 'Filtered!'; });
+		Filter::register('test-param', function($var1, $var2) { return $var1.$var2; });
+		Filter::register('test-multi-1', function() { $_SERVER['test-multi-1'] = true; });
+		Filter::register('test-multi-2', function() { $_SERVER['test-multi-2'] = true; });
+
+		$this->filter('before', 'test-all-before');
+		$this->filter('after', 'test-all-after');
+		$this->filter('before', 'test-profile-before')->only(array('profile'));
+		$this->filter('before', 'test-except')->except(array('index', 'profile'));
+		$this->filter('before', 'test-on-post')->on(array('post'));
+		$this->filter('before', 'test-on-get-put')->on(array('get', 'put'));
+		$this->filter('before', 'test-before-filter')->only('login');
+		$this->filter('after', 'test-before-filter')->only('logout');
+		$this->filter('before', 'test-param:1,2')->only('edit');
+		$this->filter('before', 'test-multi-1|test-multi-2')->only('save');
+	}
+
+	public function action_index()
+	{
+		return __FUNCTION__;
+	}
+
+	public function action_profile()
+	{
+		return __FUNCTION__;
+	}
+
+	public function action_show()
+	{
+		return __FUNCTION__;
+	}
+
+	public function action_edit()
+	{
+		return __FUNCTION__;
+	}
+
+	public function action_save()
+	{
+		return __FUNCTION__;
+	}
+
+	public function action_login()
+	{
+		return __FUNCTION__;
+	}
+
+	public function action_logout()
+	{
+		return __FUNCTION__;
+	}
+
+}

+ 42 - 0
laravel/tests/application/controllers/home.php

@@ -0,0 +1,42 @@
+<?php
+
+class Home_Controller extends Controller {
+
+	/*
+	|--------------------------------------------------------------------------
+	| The Default Controller
+	|--------------------------------------------------------------------------
+	|
+	| Instead of using RESTful routes and anonymous functions, you might wish
+	| to use controllers to organize your application API. You'll love them.
+	|
+	| To start using this controller simply remove the default route from the
+	| application "routes.php" file. Laravel is smart enough to locate this
+	| controller and call the default method, which is "action_index".
+	|
+	| This controller responds to URIs beginning with "home", and it also
+	| serves as the default controller for the application, meaning it
+	| handles requests to the root of the application.
+	|
+	| You can respond to GET requests to "/home/profile" like so:
+	|
+	|		public function action_profile()
+	|		{
+	|			return "This is your profile!";
+	|		}
+	|
+	| Any extra segments are passed to the method as parameters:
+	|
+	|		public function action_profile($id)
+	|		{
+	|			return "This is the profile for user {$id}.";
+	|		}
+	|
+	*/
+
+	public function action_index()
+	{
+		return View::make('home.index');
+	}
+
+}

+ 17 - 0
laravel/tests/application/controllers/restful.php

@@ -0,0 +1,17 @@
+<?php
+
+class Restful_Controller extends Controller {
+
+	public $restful = true;
+
+	public function get_index()
+	{
+		return __FUNCTION__;
+	}
+
+	public function post_index()
+	{
+		return __FUNCTION__;
+	}
+
+}

+ 12 - 0
laravel/tests/application/controllers/template/basic.php

@@ -0,0 +1,12 @@
+<?php
+
+class Template_Basic_Controller extends Controller {
+
+	public $layout = 'home.index';
+
+	public function action_index()
+	{
+		//
+	}
+
+}

+ 12 - 0
laravel/tests/application/controllers/template/named.php

@@ -0,0 +1,12 @@
+<?php
+
+class Template_Named_Controller extends Controller {
+
+	public $layout = 'name: home';
+
+	public function action_index()
+	{
+		//
+	}
+
+}

+ 26 - 0
laravel/tests/application/controllers/template/override.php

@@ -0,0 +1,26 @@
+<?php
+
+class TemplateStub {
+	
+	public function __toString()
+	{
+		return 'TemplateStub';
+	}
+
+}
+
+class Template_Override_Controller extends Controller {
+
+	public $layout = 'home.index';
+
+	public function action_index()
+	{
+		//
+	}
+
+	public function layout()
+	{
+		return 'Layout';
+	}
+
+}

+ 7 - 0
laravel/tests/application/dashboard/repository.php

@@ -0,0 +1,7 @@
+<?php namespace Dashboard;
+
+/**
+ * This class is used for testing the auto-loading of classes
+ * that are mapped by namesapce.
+ */
+class Repository {}

+ 19 - 0
laravel/tests/application/language/en/pagination.php

@@ -0,0 +1,19 @@
+<?php 
+
+return array(
+
+	/*
+	|--------------------------------------------------------------------------
+	| Pagination Language Lines
+	|--------------------------------------------------------------------------
+	|
+	| The following language lines are used by the paginator library to build
+	| the pagination links. You're free to change them to anything you want.
+	| If you come up with something more exciting, let us know.
+	|
+	*/
+
+	'previous' => '&laquo; Previous',
+	'next'     => 'Next &raquo;',
+
+);

+ 96 - 0
laravel/tests/application/language/en/validation.php

@@ -0,0 +1,96 @@
+<?php 
+
+return array(
+
+	/*
+	|--------------------------------------------------------------------------
+	| Validation Language Lines
+	|--------------------------------------------------------------------------
+	|
+	| The following language lines contain the default error messages used
+	| by the validator class. Some of the rules contain multiple versions,
+	| such as the size (max, min, between) rules. These versions are used
+	| for different input types such as strings and files.
+	|
+	| These language lines may be easily changed to provide custom error
+	| messages in your application. Error messages for custom validation
+	| rules may also be added to this file.
+	|
+	*/
+
+	"accepted"       => "The :attribute must be accepted.",
+	"active_url"     => "The :attribute is not a valid URL.",
+	"alpha"          => "The :attribute may only contain letters.",
+	"alpha_dash"     => "The :attribute may only contain letters, numbers, and dashes.",
+	"alpha_num"      => "The :attribute may only contain letters and numbers.",
+	"between"        => array(
+		"numeric" => "The :attribute must be between :min - :max.",
+		"file"    => "The :attribute must be between :min - :max kilobytes.",
+		"string"  => "The :attribute must be between :min - :max characters.",
+	),
+	"confirmed"      => "The :attribute confirmation does not match.",
+	"different"      => "The :attribute and :other must be different.",
+	"email"          => "The :attribute format is invalid.",
+	"exists"         => "The selected :attribute is invalid.",
+	"image"          => "The :attribute must be an image.",
+	"in"             => "The selected :attribute is invalid.",
+	"integer"        => "The :attribute must be an integer.",
+	"ip"             => "The :attribute must be a valid IP address.",
+	"max"            => array(
+		"numeric" => "The :attribute must be less than :max.",
+		"file"    => "The :attribute must be less than :max kilobytes.",
+		"string"  => "The :attribute must be less than :max characters.",
+	),
+	"mimes"          => "The :attribute must be a file of type: :values.",
+	"min"            => array(
+		"numeric" => "The :attribute must be at least :min.",
+		"file"    => "The :attribute must be at least :min kilobytes.",
+		"string"  => "The :attribute must be at least :min characters.",
+	),
+	"not_in"         => "The selected :attribute is invalid.",
+	"numeric"        => "The :attribute must be a number.",
+	"required"       => "The :attribute field is required.",
+	"same"           => "The :attribute and :other must match.",
+	"size"           => array(
+		"numeric" => "The :attribute must be :size.",
+		"file"    => "The :attribute must be :size kilobyte.",
+		"string"  => "The :attribute must be :size characters.",
+	),
+	"unique"         => "The :attribute has already been taken.",
+	"url"            => "The :attribute format is invalid.",
+
+	/*
+	|--------------------------------------------------------------------------
+	| Custom Validation Language Lines
+	|--------------------------------------------------------------------------
+	|
+	| Here you may specify custom validation messages for attributes using the
+	| convention "attribute_rule" to name the lines. This helps keep your
+	| custom validation clean and tidy.
+	|
+	| So, say you want to use a custom validation message when validating that
+	| the "email" attribute is unique. Just add "email_unique" to this array
+	| with your custom message. The Validator will handle the rest!
+	|
+	*/
+
+	'custom' => array('custom_required' => 'This field is required!'),
+
+	/*
+	|--------------------------------------------------------------------------
+	| Validation Attributes
+	|--------------------------------------------------------------------------
+	|
+	| The following language lines are used to swap attribute place-holders
+	| with something more reader friendly such as "E-Mail Address" instead
+	| of "email". Your users will thank you.
+	|
+	| The Validator class will automatically search this array of lines it
+	| is attempting to replace the :attribute place-holder in messages.
+	| It's pretty slick. We think you'll like it.
+	|
+	*/
+
+	'attributes' => array('test_attribute' => 'attribute'),
+
+);

+ 7 - 0
laravel/tests/application/language/sp/validation.php

@@ -0,0 +1,7 @@
+<?php
+
+return array(
+
+	'required' => 'El campo de atributo es necesario.',
+
+);

+ 0 - 0
laravel/tests/application/libraries/.gitignore


+ 0 - 0
laravel/tests/application/migrations/.gitignore


+ 0 - 0
laravel/tests/application/models/.gitignore


+ 3 - 0
laravel/tests/application/models/autoloader.php

@@ -0,0 +1,3 @@
+<?php
+
+class Autoloader_HardCoded {}

+ 3 - 0
laravel/tests/application/models/repositories/user.php

@@ -0,0 +1,3 @@
+<?php namespace Repositories;
+
+class User {}

+ 3 - 0
laravel/tests/application/models/user.php

@@ -0,0 +1,3 @@
+<?php
+
+class User {}

+ 93 - 0
laravel/tests/application/routes.php

@@ -0,0 +1,93 @@
+<?php
+
+/*
+|--------------------------------------------------------------------------
+| Application Routes
+|--------------------------------------------------------------------------
+|
+| Simply tell Laravel the HTTP verbs and URIs it should respond to. It is a
+| breeze to setup your applications using Laravel's RESTful routing, and it
+| is perfectly suited for building both large applications and simple APIs.
+| Enjoy the fresh air and simplicity of the framework.
+|
+| Let's respond to a simple GET request to http://example.com/hello:
+|
+|		Router::register('GET /hello', function()
+|		{
+|			return 'Hello World!';
+|		});
+|
+| You can even respond to more than one URI:
+|
+|		Router::register('GET /hello, GET /world', function()
+|		{
+|			return 'Hello World!';
+|		});
+|
+| It's easy to allow URI wildcards using (:num) or (:any):
+|
+|		Router::register('GET /hello/(:any)', function($name)
+|		{
+|			return "Welcome, $name.";
+|		});
+|
+*/
+
+Route::get('/, home', array('as' => 'home', function()
+{
+	return View::make('home.index');
+}));
+
+Route::controller(array(
+	'auth', 'filter', 'home', 'restful',
+	'template.basic', 'template.name', 'template.override',
+	'admin.panel',
+));
+
+/*
+|--------------------------------------------------------------------------
+| Route Filters
+|--------------------------------------------------------------------------
+|
+| Filters provide a convenient method for attaching functionality to your
+| routes. The built-in "before" and "after" filters are called before and
+| after every request to your application, and you may even create other
+| filters that can be attached to individual routes.
+|
+| Let's walk through an example...
+|
+| First, define a filter:
+|
+|		Filter::register('filter', function()
+|		{
+|			return 'Filtered!';
+|		});
+|
+| Next, attach the filter to a route:
+|
+|		Router::register('GET /', array('before' => 'filter', function()
+|		{
+|			return 'Hello World!';
+|		}));
+|
+*/
+
+Filter::register('before', function()
+{
+	$_SERVER['before'] = true;
+});
+
+Filter::register('after', function()
+{
+	$_SERVER['after'] = true;
+});
+
+Filter::register('csrf', function()
+{
+	if (Request::forged()) return Response::error('500');
+});
+
+Filter::register('auth', function()
+{
+	if (Auth::guest()) return Redirect::to('login');
+});

+ 157 - 0
laravel/tests/application/start.php

@@ -0,0 +1,157 @@
+<?php
+
+/*
+|--------------------------------------------------------------------------
+| PHP Display Errors Configuration
+|--------------------------------------------------------------------------
+|
+| Since Laravel intercepts and displays all errors with a detailed stack
+| trace, we can turn off the display_errors ini directive. However, you
+| may want to enable this option if you ever run into a dreaded white
+| screen of death, as it can provide some clues.
+|
+*/
+
+ini_set('display_errors', 'On');
+
+/*
+|--------------------------------------------------------------------------
+| Laravel Configuration Loader
+|--------------------------------------------------------------------------
+|
+| The Laravel configuration loader is responsible for returning an array
+| of configuration options for a given bundle and file. By default, we
+| use the files provided with Laravel; however, you are free to use
+| your own storage mechanism for configuration arrays.
+|
+*/
+
+Laravel\Event::listen(Laravel\Config::loader, function($bundle, $file)
+{
+	return Laravel\Config::file($bundle, $file);
+});
+
+/*
+|--------------------------------------------------------------------------
+| Register Class Aliases
+|--------------------------------------------------------------------------
+|
+| Aliases allow you to use classes without always specifying their fully
+| namespaced path. This is convenient for working with any library that
+| makes a heavy use of namespace for class organization. Here we will
+| simply register the configured class aliases.
+|
+*/
+
+$aliases = Laravel\Config::get('application.aliases');
+
+Laravel\Autoloader::$aliases = $aliases;
+
+/*
+|--------------------------------------------------------------------------
+| Auto-Loader Mappings
+|--------------------------------------------------------------------------
+|
+| Registering a mapping couldn't be easier. Just pass an array of class
+| to path maps into the "map" function of Autoloader. Then, when you
+| want to use that class, just use it. It's simple!
+|
+*/
+
+Autoloader::map(array(
+	'Base_Controller' => path('app').'controllers/base.php',
+));
+
+/*
+|--------------------------------------------------------------------------
+| Auto-Loader Directories
+|--------------------------------------------------------------------------
+|
+| The Laravel auto-loader can search directories for files using the PSR-0
+| naming convention. This convention basically organizes classes by using
+| the class namespace to indicate the directory structure.
+|
+*/
+
+Autoloader::directories(array(
+	path('app').'models',
+	path('app').'libraries',
+));
+
+/*
+|--------------------------------------------------------------------------
+| Laravel View Loader
+|--------------------------------------------------------------------------
+|
+| The Laravel view loader is responsible for returning the full file path
+| for the given bundle and view. Of course, a default implementation is
+| provided to load views according to typical Laravel conventions but
+| you may change this to customize how your views are organized.
+|
+*/
+
+Event::listen(View::loader, function($bundle, $view)
+{
+	return View::file($bundle, $view, Bundle::path($bundle).'views');
+});
+
+/*
+|--------------------------------------------------------------------------
+| Laravel Language Loader
+|--------------------------------------------------------------------------
+|
+| The Laravel language loader is responsible for returning the array of
+| language lines for a given bundle, language, and "file". A default
+| implementation has been provided which uses the default language
+| directories included with Laravel.
+|
+*/
+
+Event::listen(Lang::loader, function($bundle, $language, $file)
+{
+	return Lang::file($bundle, $language, $file);
+});
+
+/*
+|--------------------------------------------------------------------------
+| Enable The Blade View Engine
+|--------------------------------------------------------------------------
+|
+| The Blade view engine provides a clean, beautiful templating language
+| for your application, including syntax for echoing data and all of
+| the typical PHP control structures. We'll simply enable it here.
+|
+*/
+
+Blade::sharpen();
+
+/*
+|--------------------------------------------------------------------------
+| Set The Default Timezone
+|--------------------------------------------------------------------------
+|
+| We need to set the default timezone for the application. This controls
+| the timezone that will be used by any of the date methods and classes
+| utilized by Laravel or your application. The timezone may be set in
+| your application configuration file.
+|
+*/
+
+date_default_timezone_set(Config::get('application.timezone'));
+
+/*
+|--------------------------------------------------------------------------
+| Start / Load The User Session
+|--------------------------------------------------------------------------
+|
+| Sessions allow the web, which is stateless, to simulate state. In other
+| words, sessions allow you to store information about the current user
+| and state of your application. Here we'll just fire up the session
+| if a session driver has been configured.
+|
+*/
+
+if ( ! Request::cli() and Config::get('session.driver') !== '')
+{
+	Session::load();
+}

+ 0 - 0
laravel/tests/application/tasks/.gitignore


+ 103 - 0
laravel/tests/application/views/error/404.php

@@ -0,0 +1,103 @@
+<!doctype html>
+<html>
+	<head>
+		<meta charset="utf-8">
+
+		<title>Error 404 - Not Found</title>
+
+		<style>
+			@import url(http://fonts.googleapis.com/css?family=Ubuntu);
+
+			body {
+				background: #eee;
+				color: #6d6d6d;
+				font: normal normal normal 14px/1.253 Ubuntu, sans-serif;
+				margin: 0 0 25px 0;
+				min-width: 800px;
+				padding: 0;
+			}
+
+			#main {
+				background-clip: padding-box;
+				background-color: #fff;
+				border:1px solid #ccc;
+				border-radius: 5px;
+				box-shadow: 0 0 10px #cdcdcd;
+				margin: 25px auto 0;
+				padding: 30px;
+				width: 700px;
+				position: relative;
+			}
+
+			#main h1 {
+				font-family: 'Ubuntu';
+				font-size: 38px;
+				letter-spacing: 2px;
+				margin: 0 0 10px 0;
+				padding: 0;
+			}
+
+			#main h2 {
+				color: #999;
+				font-size: 18px;
+				letter-spacing: 3px;
+				margin: 0 0 25px 0;
+				padding: 0 0 0 0;
+			}
+
+			#main h3 {
+				color: #999;
+				margin-top: 24px;
+				padding: 0 0 0 0;
+			}
+
+			#main h3 {
+				font-size: 18px;
+			}
+
+			#main p {
+				line-height: 25px;
+				margin: 10px 0;
+			}
+
+			#main pre {
+				background-color: #333;
+				border-left: 1px solid #d8d8d8;
+				border-top: 1px solid #d8d8d8;
+				border-radius: 5px;
+				color: #eee;
+				padding: 10px;
+			}
+
+			#main ul {
+				margin: 10px 0;
+				padding: 0 30px;
+			}
+
+			#main li {
+				margin: 5px 0;
+			}
+		</style>
+	</head>
+	<body>
+		<div id="main">
+			<?php $messages = array('We need a map.', 'I think we\'re lost.', 'We took a wrong turn.'); ?>
+
+			<h1><?php echo $messages[mt_rand(0, 2)]; ?></h1>
+
+			<h2>Server Error: 404 (Not Found)</h2>
+
+			<h3>What does this mean?</h3>
+
+			<p>
+				We couldn't find the page you requested on our servers. We're really sorry
+				about that. It's our fault, not yours. We'll work hard to get this page
+				back online as soon as possible.
+			</p>
+
+			<p>
+				Perhaps you would like to go to our <?php echo HTML::link('/', 'home page'); ?>?
+			</p>
+		</div>
+	</body>
+</html>

+ 103 - 0
laravel/tests/application/views/error/500.php

@@ -0,0 +1,103 @@
+<!doctype html>
+<html>
+	<head>
+		<meta charset="utf-8">
+
+		<title>Error 500 - Internal Server Error</title>
+
+		<style>
+			@import url(http://fonts.googleapis.com/css?family=Ubuntu);
+
+			body {
+				background: #eee;
+				color: #6d6d6d;
+				font: normal normal normal 14px/1.253 Ubuntu, sans-serif;
+				margin: 0 0 25px 0;
+				min-width: 800px;
+				padding: 0;
+			}
+
+			#main {
+				background-clip: padding-box;
+				background-color: #fff;
+				border:1px solid #ccc;
+				border-radius: 5px;
+				box-shadow: 0 0 10px #cdcdcd;
+				margin: 25px auto 0;
+				padding: 30px;
+				width: 700px;
+				position: relative;
+			}
+
+			#main h1 {
+				font-family: 'Ubuntu';
+				font-size: 38px;
+				letter-spacing: 2px;
+				margin: 0 0 10px 0;
+				padding: 0;
+			}
+
+			#main h2 {
+				color: #999;
+				font-size: 18px;
+				letter-spacing: 3px;
+				margin: 0 0 25px 0;
+				padding: 0 0 0 0;
+			}
+
+			#main h3 {
+				color: #999;
+				margin-top: 24px;
+				padding: 0 0 0 0;
+			}
+
+			#main h3 {
+				font-size: 18px;
+			}
+
+			#main p {
+				line-height: 25px;
+				margin: 10px 0;
+			}
+
+			#main pre {
+				background-color: #333;
+				border-left: 1px solid #d8d8d8;
+				border-top: 1px solid #d8d8d8;
+				border-radius: 5px;
+				color: #eee;
+				padding: 10px;
+			}
+
+			#main ul {
+				margin: 10px 0;
+				padding: 0 30px;
+			}
+
+			#main li {
+				margin: 5px 0;
+			}
+		</style>
+	</head>
+	<body>
+		<div id="main">
+			<?php $messages = array('Ouch.', 'Oh no!', 'Whoops!'); ?>
+
+			<h1><?php echo $messages[mt_rand(0, 2)]; ?></h1>
+
+			<h2>Server Error: 500 (Internal Server Error)</h2>
+
+			<h3>What does this mean?</h3>
+
+			<p>
+				Something went wrong on our servers while we were processing your request.
+				We're really sorry about this, and will work hard to get this resolved as
+				soon as possible.
+			</p>
+
+			<p>
+				Perhaps you would like to go to our <?php echo HTML::link('/', 'home page'); ?>?
+			</p>
+		</div>
+	</body>
+</html>

+ 122 - 0
laravel/tests/application/views/home/index.php

@@ -0,0 +1,122 @@
+<!doctype html>
+<html>
+	<head>
+		<meta charset="utf-8">
+
+		<title>Laravel - A Framework For Web Artisans</title>
+
+		<style>
+			@import url(http://fonts.googleapis.com/css?family=Ubuntu);
+
+			body {
+				background: #eee;
+				color: #6d6d6d;
+				font: normal normal normal 14px/1.253 Ubuntu, sans-serif;
+				margin: 0 0 25px 0;
+				min-width: 800px;
+				padding: 0;
+			}
+
+			#main {
+				background-clip: padding-box;
+				background-color: #fff;
+				border:1px solid #ccc;
+				border-radius: 5px;
+				box-shadow: 0 0 10px #cdcdcd;
+				margin: 25px auto 0;
+				padding: 30px;
+				width: 700px;
+				position: relative;
+			}
+
+			#main h1 {
+				font-family: 'Ubuntu';
+				font-size: 38px;
+				letter-spacing: 2px;
+				margin: 0 0 10px 0;
+				padding: 0;
+			}
+
+			#main h2 {
+				color: #999;
+				font-size: 18px;
+				letter-spacing: 3px;
+				margin: 0 0 25px 0;
+				padding: 0 0 0 0;
+			}
+
+			#main h3 {
+				color: #999;
+				margin-top: 24px;
+				padding: 0 0 0 0;
+			}
+
+			#main h3 {
+				font-size: 18px;
+			}
+
+			#main p {
+				line-height: 25px;
+				margin: 10px 0;
+			}
+
+			#main pre {
+				background-color: #333;
+				border-left: 1px solid #d8d8d8;
+				border-top: 1px solid #d8d8d8;
+				border-radius: 5px;
+				color: #eee;
+				padding: 10px;
+			}
+
+			#main ul {
+				margin: 10px 0;
+				padding: 0 30px;
+			}
+
+			#main li {
+				margin: 5px 0;
+			}
+		</style>
+	</head>
+	<body>
+		<div id="main">
+			<h1>Welcome To Laravel</h1>
+
+			<h2>A Framework For Web Artisans</h2>
+
+			<p>
+				You have successfully installed the Laravel framework. Laravel is a simple framework
+				that helps web artisans create beautiful, creative applications using elegant, expressive
+				syntax. You'll love using it.
+			</p>
+
+			<h3>Learn the terrain.</h3>
+
+			<p>
+				You've landed yourself on our default home page. The route that
+				is generating this page lives at:
+			</p>
+
+			<pre><code>APP_PATH/routes.php</code></pre>
+
+			<p>And the view sitting before you can be found at:</p>
+
+			<pre><code>APP_PATH/views/home/index.php</code></pre>
+
+			<h3>Create something beautiful.</h3>
+
+			<p>
+				Now that you're up and running, it's time to start creating!
+				Here are some links to help you get started:
+			</p>
+
+			<ul>
+				<li><a href="http://laravel.com">Official Website</a></li>
+				<li><a href="http://forums.laravel.com">Laravel Forums</a></li>
+				<li><a href="http://github.com/laravel/laravel">GitHub Repository</a></li>
+			</ul>
+
+		</div>
+	</body>
+</html>

+ 1 - 0
laravel/tests/application/views/tests/basic.php

@@ -0,0 +1 @@
+<?php echo $name; ?> is <?php echo $age; ?>

+ 1 - 0
laravel/tests/application/views/tests/nested.php

@@ -0,0 +1 @@
+Taylor

+ 0 - 0
laravel/tests/bundles/.gitignore


+ 7 - 0
laravel/tests/bundles/dashboard/config/meta.php

@@ -0,0 +1,7 @@
+<?php
+
+return array(
+
+	'bundle' => 'dashboard',
+
+);

+ 10 - 0
laravel/tests/bundles/dashboard/controllers/panel.php

@@ -0,0 +1,10 @@
+<?php
+
+class Dashboard_Panel_Controller extends Controller {
+
+	public function action_index()
+	{
+		return 'Dashboard_Panel_Index';
+	}
+
+}

+ 7 - 0
laravel/tests/bundles/dashboard/models/repository.php

@@ -0,0 +1,7 @@
+<?php namespace Dashboard;
+
+/**
+ * This class is used for testing the auto-loading of classes
+ * that are mapped by namesapce.
+ */
+class Repository {}

+ 8 - 0
laravel/tests/bundles/dashboard/routes.php

@@ -0,0 +1,8 @@
+<?php
+
+Route::get('dashboard', array('as' => 'dashboard', function()
+{
+	//
+}));
+
+Route::controller('dashboard::panel');

+ 6 - 0
laravel/tests/bundles/dummy/routes.php

@@ -0,0 +1,6 @@
+<?php
+
+if (isset($_SERVER['bundle.dummy.routes']))
+{
+	$_SERVER['bundle.dummy.routes']++;
+}

+ 3 - 0
laravel/tests/bundles/dummy/start.php

@@ -0,0 +1,3 @@
+<?php
+
+$_SERVER['bundle.dummy.start']++;

+ 258 - 0
laravel/tests/cases/asset.test.php

@@ -0,0 +1,258 @@
+<?php
+
+class AssetTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Initialize the test environment.
+	 */
+	public function setUp()
+	{
+		Config::$items = array();
+		Config::$cache = array();
+		Asset::$containers = array();
+	}
+
+	/**
+	 * Test the Asset::container method.
+	 *
+	 * @group laravel
+	 */
+	public function testContainersCanBeCreated()
+	{
+		$container = Asset::container('foo');
+
+		$this->assertTrue($container === Asset::container('foo'));
+		$this->assertInstanceOf('\\Laravel\\Asset_Container', $container);
+	}
+
+	/**
+	 * Test the Asset::container method for default container creation.
+	 *
+	 * @group laravel
+	 */
+	public function testDefaultContainerCreatedByDefault()
+	{
+		$this->assertEquals('default', Asset::container()->name);
+	}
+
+	/**
+	 * Test the Asset::__callStatic method.
+	 *
+	 * @group laravel
+	 */
+	public function testContainerMethodsCanBeDynamicallyCalled()
+	{
+		Asset::style('common', 'common.css');
+
+		$this->assertEquals('common.css', Asset::container()->assets['style']['common']['source']);
+	}
+
+	/**
+	 * Test the Asset_Container constructor.
+	 *
+	 * @group laravel
+	 */
+	public function testNameIsSetOnAssetContainerConstruction()
+	{
+		$container = $this->getContainer();
+
+		$this->assertEquals('foo', $container->name);
+	}
+
+	/**
+	 * Test the Asset_Container::add method.
+	 *
+	 * @group laravel
+	 */
+	public function testAddMethodProperlySniffsAssetType()
+	{
+		$container = $this->getContainer();
+
+		$container->add('jquery', 'jquery.js');
+		$container->add('common', 'common.css');
+
+		$this->assertEquals('jquery.js', $container->assets['script']['jquery']['source']);
+		$this->assertEquals('common.css', $container->assets['style']['common']['source']);
+	}
+
+	/**
+	 * Test the Asset_Container::style method.
+	 *
+	 * @group laravel
+	 */
+	public function testStyleMethodProperlyRegistersAnAsset()
+	{
+		$container = $this->getContainer();
+
+		$container->style('common', 'common.css');
+
+		$this->assertEquals('common.css', $container->assets['style']['common']['source']);
+	}
+
+	/**
+	 * Test the Asset_Container::style method sets media attribute.
+	 *
+	 * @group laravel
+	 */
+	public function testStyleMethodProperlySetsMediaAttributeIfNotSet()
+	{
+		$container = $this->getContainer();
+
+		$container->style('common', 'common.css');
+
+		$this->assertEquals('all', $container->assets['style']['common']['attributes']['media']);
+	}
+
+	/**
+	 * Test the Asset_Container::style method sets media attribute.
+	 *
+	 * @group laravel
+	 */
+	public function testStyleMethodProperlyIgnoresMediaAttributeIfSet()
+	{
+		$container = $this->getContainer();
+
+		$container->style('common', 'common.css', array(), array('media' => 'print'));
+
+		$this->assertEquals('print', $container->assets['style']['common']['attributes']['media']);
+	}
+
+	/**
+	 * Test the Asset_Container::script method.
+	 *
+	 * @group laravel
+	 */
+	public function testScriptMethodProperlyRegistersAnAsset()
+	{
+		$container = $this->getContainer();
+
+		$container->script('jquery', 'jquery.js');
+
+		$this->assertEquals('jquery.js', $container->assets['script']['jquery']['source']);
+	}
+
+	/**
+	 * Test the Asset_Container::add method properly sets dependencies.
+	 *
+	 * @group laravel
+	 */
+	public function testAddMethodProperlySetsDependencies()
+	{
+		$container = $this->getContainer();
+
+		$container->add('common', 'common.css', 'jquery');
+		$container->add('jquery', 'jquery.js', array('jquery-ui'));
+
+		$this->assertEquals(array('jquery'), $container->assets['style']['common']['dependencies']);
+		$this->assertEquals(array('jquery-ui'), $container->assets['script']['jquery']['dependencies']);
+	}
+
+	/**
+	 * Test the Asset_Container::add method properly sets attributes.
+	 *
+	 * @group laravel
+	 */
+	public function testAddMethodProperlySetsAttributes()
+	{
+		$container = $this->getContainer();
+
+		$container->add('common', 'common.css', array(), array('media' => 'print'));
+		$container->add('jquery', 'jquery.js', array(), array('defer'));
+
+		$this->assertEquals(array('media' => 'print'), $container->assets['style']['common']['attributes']);
+		$this->assertEquals(array('defer'), $container->assets['script']['jquery']['attributes']);
+	}
+
+	/**
+	 * Test the Asset_Container::bundle method.
+	 *
+	 * @group laravel
+	 */
+	public function testBundleMethodCorrectlySetsTheAssetBundle()
+	{
+		$container = $this->getContainer();
+
+		$container->bundle('eloquent');
+
+		$this->assertEquals('eloquent', $container->bundle);
+	}
+
+	/**
+	 * Test the Asset_Container::path method.
+	 *
+	 * @group laravel
+	 */
+	public function testPathMethodReturnsCorrectPathForABundleAsset()
+	{
+		$container = $this->getContainer();
+
+		$container->bundle('eloquent');
+
+		$this->assertEquals('/bundles/eloquent/foo.jpg', $container->path('foo.jpg'));
+	}
+
+	/**
+	 * Test the Asset_Container::path method.
+	 *
+	 * @group laravel
+	 */
+	public function testPathMethodReturnsCorrectPathForAnApplicationAsset()
+	{
+		$container = $this->getContainer();
+
+		$this->assertEquals('/foo.jpg', $container->path('foo.jpg'));
+	}
+
+	/**
+	 * Test the Asset_Container::scripts method.
+	 *
+	 * @group laravel
+	 */
+	public function testScriptsCanBeRetrieved()
+	{
+		$container = $this->getContainer();
+
+		$container->script('dojo', 'dojo.js', array('jquery-ui'));
+		$container->script('jquery', 'jquery.js', array('jquery-ui', 'dojo'));
+		$container->script('jquery-ui', 'jquery-ui.js');
+
+		$scripts = $container->scripts();
+
+		$this->assertTrue(strpos($scripts, 'jquery.js') > 0);
+		$this->assertTrue(strpos($scripts, 'jquery.js') > strpos($scripts, 'jquery-ui.js'));
+		$this->assertTrue(strpos($scripts, 'dojo.js') > strpos($scripts, 'jquery-ui.js'));
+	}
+
+	/**
+	 * Test the Asset_Container::styles method.
+	 *
+	 * @group laravel
+	 */
+	public function testStylesCanBeRetrieved()
+	{
+		$container = $this->getContainer();
+
+		$container->style('dojo', 'dojo.css', array('jquery-ui'), array('media' => 'print'));
+		$container->style('jquery', 'jquery.css', array('jquery-ui', 'dojo'));
+		$container->style('jquery-ui', 'jquery-ui.css');
+
+		$styles = $container->styles();
+
+		$this->assertTrue(strpos($styles, 'jquery.css') > 0);
+		$this->assertTrue(strpos($styles, 'media="print"') > 0);
+		$this->assertTrue(strpos($styles, 'jquery.css') > strpos($styles, 'jquery-ui.css'));
+		$this->assertTrue(strpos($styles, 'dojo.css') > strpos($styles, 'jquery-ui.css'));
+	}
+
+	/**
+	 * Get an asset container instance.
+	 *
+	 * @param  string           $name
+	 * @return Asset_Container
+	 */
+	private function getContainer($name = 'foo')
+	{
+		return new Laravel\Asset_Container($name);
+	}
+
+}

+ 359 - 0
laravel/tests/cases/auth.test.php

@@ -0,0 +1,359 @@
+<?php
+
+use Symfony\Component\HttpFoundation\LaravelRequest as RequestFoundation;
+
+use Laravel\Str;
+use Laravel\Auth;
+use Laravel\Cookie;
+use Laravel\Session;
+use Laravel\Crypter;
+use Laravel\Session\Payload;
+
+class AuthTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Setup teh test environment.
+	 */
+	public function setUp()
+	{
+		$_SERVER['auth.login.stub'] = null;
+		Cookie::$jar = array();
+		Config::$items = array();
+		Auth::driver()->user = null;
+		Session::$instance = null;
+		Config::set('database.default', 'sqlite');
+	}
+
+	/**
+	 * Tear down the test environment.
+	 */
+	public function tearDown()
+	{
+		$_SERVER['auth.login.stub'] = null;
+		Cookie::$jar = array();
+		Config::$items = array();
+		Auth::driver()->user = null;
+		Session::$instance = null;
+		Config::set('database.default', 'mysql');
+	}
+
+	/**
+	 * Set one of the $_SERVER variables.
+	 *
+	 * @param string  $key
+	 * @param string  $value
+	 */
+	protected function setServerVar($key, $value)
+	{
+		$_SERVER[$key] = $value;
+
+		$this->restartRequest();
+	}
+
+	/**
+	 * Reinitialize the global request.
+	 * 
+	 * @return void
+	 */
+	protected function restartRequest()
+	{
+		// FIXME: Ugly hack, but old contents from previous requests seem to
+		// trip up the Foundation class.
+		$_FILES = array();
+
+		Request::$foundation = RequestFoundation::createFromGlobals();
+	}
+
+	/**
+	 * Test the Auth::user method.
+	 *
+	 * @group laravel
+	 */
+	public function testUserMethodReturnsCurrentUser()
+	{
+		Auth::driver()->user = 'Taylor';
+
+		$this->assertEquals('Taylor', Auth::user());
+	}
+
+	/**
+	 * Test the Auth::check method.
+	 *
+	 * @group laravel
+	 */
+	public function testCheckMethodReturnsTrueWhenUserIsSet()
+	{
+		$auth = new AuthUserReturnsDummy;
+
+		$this->assertTrue($auth->check());
+	}
+
+	/**
+	 * Test the Auth::check method.
+	 *
+	 * @group laravel
+	 */
+	public function testCheckMethodReturnsFalseWhenNoUserIsSet()
+	{
+		$auth = new AuthUserReturnsNull;
+
+		$this->assertFalse($auth->check());
+	}
+
+	/**
+	 * Test the Auth::guest method.
+	 *
+	 * @group laravel
+	 */
+	public function testGuestReturnsTrueWhenNoUserIsSet()
+	{
+		$auth = new AuthUserReturnsNull;
+
+		$this->assertTrue($auth->guest());
+	}
+
+	/**
+	 * Test the Auth::guest method.
+	 *
+	 * @group laravel
+	 */
+	public function testGuestReturnsFalseWhenUserIsSet()
+	{
+		$auth = new AuthUserReturnsDummy;
+		
+		$this->assertFalse($auth->guest());
+	}
+
+	/**
+	 * Test the Auth::user method.
+	 *
+	 * @group laravel
+	 */
+	public function testUserMethodReturnsNullWhenNoUserExistsAndNoRecallerExists()
+	{
+		Session::$instance = new Payload($this->getMock('Laravel\\Session\\Drivers\\Driver'));
+
+		$this->assertNull(Auth::user());
+	}
+
+	/**
+	 * Test the Auth::user method.
+	 *
+	 * @group laravel
+	 */
+	public function testUserReturnsUserByID()
+	{
+		Session::$instance = new Payload($this->getMock('Laravel\\Session\\Drivers\\Driver'));
+		
+		Auth::login(1);
+
+		$this->assertEquals('Taylor Otwell', Auth::user()->name);
+
+		Auth::logout();
+	}
+
+	/**
+	 * Test the Auth::user method.
+	 *
+	 * @group laravel
+	 */
+	public function testNullReturnedWhenUserIDNotValidInteger()
+	{
+		Session::$instance = new Payload($this->getMock('Laravel\\Session\\Drivers\\Driver'));
+		
+		Auth::login('asdlkasd');
+
+		$this->assertNull(Auth::user());
+	}
+
+	/**
+	 * Test the Auth::recall method.
+	 *
+	 * @group laravel
+	 */
+	public function testUserCanBeRecalledViaCookie()
+	{
+		Session::$instance = new Payload($this->getMock('Laravel\\Session\\Drivers\\Driver'));
+
+		$cookie = Crypter::encrypt('1|'.Str::random(40));
+		Cookie::forever('authloginstub_remember', $cookie);
+
+		$auth = new AuthLoginStub;
+
+		$this->assertEquals('Taylor Otwell', $auth->user()->name);
+		
+		$this->assertTrue($auth->user()->id === $_SERVER['auth.login.stub']['user']);
+	}
+
+	/**
+	 * Test the Auth::attempt method.
+	 *
+	 * @group laravel
+	 */
+	public function testAttemptMethodReturnsFalseWhenCredentialsAreInvalid()
+	{
+		$this->assertFalse(Auth::attempt(array('username' => 'foo', 'password' => 'foo')));
+		$this->assertFalse(Auth::attempt(array('username' => 'foo', 'password' => null)));
+		$this->assertFalse(Auth::attempt(array('username' => null, 'password' => null)));
+		$this->assertFalse(Auth::attempt(array('username' => 'taylor', 'password' => 'password')));
+		$this->assertFalse(Auth::attempt(array('username' => 'taylor', 'password' => 232)));
+	}
+
+	/**
+	 * Test the Auth::attempt method.
+	 *
+	 * @group laravel
+	 */
+	public function testAttemptReturnsTrueWhenCredentialsAreCorrect()
+	{
+		Session::$instance = new Payload($this->getMock('Laravel\\Session\\Drivers\\Driver'));
+
+		$auth = new AuthLoginStub;
+
+		$this->assertTrue($auth->attempt(array('username' => 'taylor', 'password' => 'password1')));
+		$this->assertEquals('1', $_SERVER['auth.login.stub']['user']);
+		$this->assertFalse($_SERVER['auth.login.stub']['remember']);
+
+		$auth_secure = new AuthLoginStub;
+
+		$this->assertTrue($auth_secure->attempt(array('username' => 'taylor', 'password' => 'password1', 'remember' => true)));
+		$this->assertEquals('1', $_SERVER['auth.login.stub']['user']);
+		$this->assertTrue($_SERVER['auth.login.stub']['remember']);
+
+		$auth_secure->logout();
+		$auth->logout();
+	}
+
+	/**
+	 * Test Auth::login method.
+	 *
+	 * @group laravel
+	 */
+	public function testLoginMethodStoresUserKeyInSession()
+	{
+		Session::$instance = new Payload($this->getMock('Laravel\\Session\\Drivers\\Driver'));
+
+		$user = new StdClass;
+		$user->id = 10;
+		Auth::login($user);
+		// FIXME: Not sure whether hard-coding the key is a good idea.
+		$user = Session::$instance->session['data']['laravel_auth_drivers_fluent_login'];
+		$this->assertEquals(10, $user->id);
+
+
+		Auth::logout();
+
+		Auth::login(5);
+		$user = Session::$instance->session['data']['laravel_auth_drivers_fluent_login'];
+		$this->assertEquals(5, $user);
+		Auth::logout(5);
+	}
+
+	/**
+	 * Test the Auth::login method.
+	 *
+	 * @group laravel
+	 */
+	public function testLoginStoresRememberCookieWhenNeeded()
+	{
+		Session::$instance = new Payload($this->getMock('Laravel\\Session\\Drivers\\Driver'));
+
+		$this->setServerVar('HTTPS', 'on');
+
+		// Set the session vars to make sure remember cookie uses them
+		Config::set('session.path', 'foo');
+		Config::set('session.domain', 'bar');
+		Config::set('session.secure', true);
+
+		Auth::login(1, true);
+
+		$this->assertTrue(isset(Cookie::$jar['laravel_auth_drivers_fluent_remember']));
+
+		$cookie = Cookie::$jar['laravel_auth_drivers_fluent_remember']['value'];
+		$cookie = explode('|', Crypter::decrypt($cookie));
+		$this->assertEquals(1, $cookie[0]);
+		$this->assertEquals('foo', Cookie::$jar['laravel_auth_drivers_fluent_remember']['path']);
+		$this->assertEquals('bar', Cookie::$jar['laravel_auth_drivers_fluent_remember']['domain']);
+		$this->assertTrue(Cookie::$jar['laravel_auth_drivers_fluent_remember']['secure']);
+
+		Auth::logout();
+
+		$this->setServerVar('HTTPS', 'off');
+	}
+
+	/**
+	 * Test the Auth::logout method.
+	 *
+	 * @group laravel
+	 */
+	public function testLogoutMethodLogsOutUser()
+	{
+		Session::$instance = new Payload($this->getMock('Laravel\\Session\\Drivers\\Driver'));
+		
+		$data = Session::$instance->session['data']['laravel_auth_drivers_fluent_login'] = 1;
+
+		Auth::logout();
+
+		// A workaround since Cookie will is only stored in memory, until Response class is called.
+		Auth::driver()->token = null;
+
+		$this->assertNull(Auth::user());
+
+		$this->assertFalse(isset(Session::$instance->session['data']['laravel_auth_drivers_fluent_login']));
+		$this->assertTrue(Cookie::$jar['laravel_auth_drivers_fluent_remember']['expiration'] < time());
+	}
+
+}
+
+class AuthUserReturnsNull extends Laravel\Auth\Drivers\Driver {
+
+	public function user() { return null; }
+
+	public function retrieve($id) { return null; }
+
+	public function attempt($arguments = array()) { return null; }
+
+}
+
+class AuthUserReturnsDummy extends Laravel\Auth\Drivers\Driver {
+
+	public function user() { return 'Taylor'; }
+
+	public function retrieve($id) { return null; }
+
+	public function attempt($arguments = array()) 
+	{
+		return $this->login($arguments['username']); 
+	}
+
+}
+
+class AuthLoginStub extends Laravel\Auth\Drivers\Fluent {
+	
+	public function login($user, $remember = false) 
+	{
+		if (is_null($remember)) $remember = false;
+
+		$_SERVER['auth.login.stub'] = compact('user', 'remember');
+
+		return parent::login($user, $remember);
+	}
+
+	public function logout()
+	{
+		parent::logout();
+	}
+
+	public function retrieve($id)
+	{
+		$user = parent::retrieve($id);
+
+		$_SERVER['auth.login.stub'] = array(
+			'user'     => $user->id,
+			'remember' => false,
+		);
+
+		return $user;
+	}
+
+}

+ 102 - 0
laravel/tests/cases/autoloader.test.php

@@ -0,0 +1,102 @@
+<?php
+
+class AutoloaderTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Test the Autoloader::map method.
+	 *
+	 * @group laravel
+	 */
+	public function testMapsCanBeRegistered()
+	{
+		Autoloader::map(array(
+			'Foo' => path('app').'models/foo.php',
+		));
+
+		$this->assertEquals(path('app').'models/foo.php', Autoloader::$mappings['Foo']);
+	}
+
+	/**
+	 * Test the Autoloader::alias method.
+	 *
+	 * @group laravel
+	 */
+	public function testAliasesCanBeRegistered()
+	{
+		Autoloader::alias('Foo\\Bar', 'Foo');
+
+		$this->assertEquals('Foo\\Bar', Autoloader::$aliases['Foo']);
+	}
+
+	/**
+	 * Test the Autoloader::directories method.
+	 *
+	 * @group laravel
+	 */
+	public function testPsrDirectoriesCanBeRegistered()
+	{
+		Autoloader::directories(array(
+			path('app').'foo'.DS.'bar',
+			path('app').'foo'.DS.'baz'.DS.DS,
+		));
+
+		$this->assertTrue(in_array(path('app').'foo'.DS.'bar'.DS, Autoloader::$directories));
+		$this->assertTrue(in_array(path('app').'foo'.DS.'baz'.DS, Autoloader::$directories));
+	}
+
+	/**
+	 * Test the Autoloader::namespaces method.
+	 *
+	 * @group laravel
+	 */
+	public function testNamespacesCanBeRegistered()
+	{
+		Autoloader::namespaces(array(
+			'Autoloader_1' => path('bundle').'autoload'.DS.'models',
+			'Autoloader_2' => path('bundle').'autoload'.DS.'libraries'.DS.DS,
+		));
+
+		$this->assertEquals(path('bundle').'autoload'.DS.'models'.DS, Autoloader::$namespaces['Autoloader_1\\']);
+		$this->assertEquals(path('bundle').'autoload'.DS.'libraries'.DS, Autoloader::$namespaces['Autoloader_2\\']);
+	}
+
+	/**
+	 * Test the loading of PSR-0 models and libraries.
+	 *
+	 * @group laravel
+	 */
+	public function testPsrLibrariesAndModelsCanBeLoaded()
+	{
+		$this->assertInstanceOf('User', new User);
+		$this->assertInstanceOf('Repositories\\User', new Repositories\User);
+	}
+
+	/**
+	 * Test the loading of hard-coded classes.
+	 *
+	 * @group laravel
+	 */
+	public function testHardcodedClassesCanBeLoaded()
+	{
+		Autoloader::map(array(
+			'Autoloader_HardCoded' => path('app').'models'.DS.'autoloader.php',
+		));
+
+		$this->assertInstanceOf('Autoloader_HardCoded', new Autoloader_HardCoded);
+	}
+
+	/**
+	 * Test the loading of classes mapped by namespaces.
+	 *
+	 * @group laravel
+	 */
+	public function testClassesMappedByNamespaceCanBeLoaded()
+	{
+		Autoloader::namespaces(array(
+			'Dashboard' => path('bundle').'dashboard'.DS.'models',
+		));
+
+		$this->assertInstanceOf('Dashboard\\Repository', new Dashboard\Repository);
+	}
+
+}

+ 63 - 0
laravel/tests/cases/blade.test.php

@@ -0,0 +1,63 @@
+<?php
+
+use Laravel\Blade;
+
+class BladeTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Test the compilation of echo statements.
+	 *
+	 * @group laravel
+	 */
+	public function testEchosAreConvertedProperly()
+	{
+		$blade1 = '{{$a}}';
+		$blade2 = '{{e($a)}}';
+
+		$this->assertEquals('<?php echo $a; ?>', Blade::compile_string($blade1));
+		$this->assertEquals('<?php echo e($a); ?>', Blade::compile_string($blade2));
+	}
+
+	/**
+	 * Test the compilation of control structures.
+	 *
+	 * @group laravel
+	 */
+	public function testControlStructuresAreCreatedCorrectly()
+	{
+		$blade1 = "@if (true)\nfoo\n@endif";
+		$blade2 = "@if (count(".'$something'.") > 0)\nfoo\n@endif";
+		$blade3 = "@if (true)\nfoo\n@elseif (false)\nbar\n@endif";
+		$blade4 = "@if (true)\nfoo\n@else\nbar\n@endif";
+
+		$this->assertEquals("<?php if(true): ?>\nfoo\n<?php endif; ?>", Blade::compile_string($blade1));
+		$this->assertEquals("<?php if(count(".'$something'.") > 0): ?>\nfoo\n<?php endif; ?>", Blade::compile_string($blade2));
+		$this->assertEquals("<?php if(true): ?>\nfoo\n<?php elseif(false): ?>\nbar\n<?php endif; ?>", Blade::compile_string($blade3));
+		$this->assertEquals("<?php if(true): ?>\nfoo\n<?php else: ?>\nbar\n<?php endif; ?>", Blade::compile_string($blade4));
+	}
+
+	/**
+	 * Test the compilation of yield statements.
+	 *
+	 * @group laravel
+	 */
+	public function testYieldsAreCompiledCorrectly()
+	{
+		$blade = "@yield('something')";
+
+		$this->assertEquals("<?php echo \\Laravel\\Section::yield('something'); ?>", Blade::compile_string($blade));
+	}
+
+	/**
+	 * Test the compilation of section statements.
+	 *
+	 * @group laravel
+	 */
+	public function testSectionsAreCompiledCorrectly()
+	{
+		$blade = "@section('something')\nfoo\n@endsection";
+
+		$this->assertEquals("<?php \\Laravel\\Section::start('something'); ?>\nfoo\n<?php \\Laravel\\Section::stop(); ?>", Blade::compile_string($blade));
+	}
+
+}

+ 251 - 0
laravel/tests/cases/bundle.test.php

@@ -0,0 +1,251 @@
+<?php
+
+class BundleTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Setup the test environment.
+	 */
+	public function setUp()
+	{
+		Bundle::$started = array();
+		Bundle::$elements = array();
+		unset(Bundle::$bundles['foo']);
+	}
+
+	/**
+	 * Tear down the test environment.
+	 */
+	public function tearDown()
+	{
+		Bundle::$started = array();
+		Bundle::$elements = array();
+		unset(Bundle::$bundles['foo']);
+	}
+
+	/**
+	 * Test Bundle::register method.
+	 *
+	 * @group laravel
+	 */
+	public function testRegisterMethodCorrectlyRegistersBundle()
+	{
+		Bundle::register('foo-baz', array('handles' => 'foo-baz'));
+		$this->assertEquals('foo-baz', Bundle::$bundles['foo-baz']['handles']);
+		$this->assertFalse(Bundle::$bundles['foo-baz']['auto']);
+
+		Bundle::register('foo-bar', array());
+		$this->assertFalse(Bundle::$bundles['foo-baz']['auto']);
+		$this->assertNull(Bundle::$bundles['foo-bar']['handles']);
+
+		unset(Bundle::$bundles['foo-baz']);
+		unset(Bundle::$bundles['foo-bar']);
+	}
+
+	/**
+	 * Test the Bundle::start method.
+	 *
+	 * @group laravel
+	 */
+	public function testStartMethodStartsBundle()
+	{
+		$_SERVER['bundle.dummy.start'] = 0;
+		$_SERVER['bundle.dummy.routes'] = 0;
+
+		$_SERVER['started.dummy'] = false;
+
+		Event::listen('laravel.started: dummy', function()
+		{
+			$_SERVER['started.dummy'] = true;
+		});
+
+		Bundle::register('dummy');
+		Bundle::start('dummy');
+
+		$this->assertTrue($_SERVER['started.dummy']);
+		$this->assertEquals(1, $_SERVER['bundle.dummy.start']);
+		$this->assertEquals(1, $_SERVER['bundle.dummy.routes']);
+
+		Bundle::start('dummy');
+
+		$this->assertEquals(1, $_SERVER['bundle.dummy.start']);
+		$this->assertEquals(1, $_SERVER['bundle.dummy.routes']);
+	}
+
+	/**
+	 * Test Bundle::handles method.
+	 *
+	 * @group laravel
+	 */
+	public function testHandlesMethodReturnsBundleThatHandlesURI()
+	{
+		Bundle::register('foo', array('handles' => 'foo-bar'));
+		$this->assertEquals('foo', Bundle::handles('foo-bar/admin'));
+		unset(Bundle::$bundles['foo']);
+	}
+
+	/**
+	 * Test the Bundle::exist method.
+	 *
+	 * @group laravel
+	 */
+	public function testExistMethodIndicatesIfBundleExist()
+	{
+		$this->assertTrue(Bundle::exists('dashboard'));
+		$this->assertFalse(Bundle::exists('foo'));
+	}
+
+	/**
+	 * Test the Bundle::started method.
+	 *
+	 * @group laravel
+	 */
+	public function testStartedMethodIndicatesIfBundleIsStarted()
+	{
+		Bundle::register('dummy');
+		Bundle::start('dummy');
+		$this->assertTrue(Bundle::started('dummy'));
+	}
+
+	/**
+	 * Test the Bundle::prefix method.
+	 *
+	 * @group laravel
+	 */
+	public function testPrefixMethodReturnsCorrectPrefix()
+	{
+		$this->assertEquals('dummy::', Bundle::prefix('dummy'));
+		$this->assertEquals('', Bundle::prefix(DEFAULT_BUNDLE));
+	}
+
+	/**
+	 * Test the Bundle::class_prefix method.
+	 *
+	 * @group laravel
+	 */
+	public function testClassPrefixMethodReturnsProperClassPrefixForBundle()
+	{
+		$this->assertEquals('Dummy_', Bundle::class_prefix('dummy'));
+		$this->assertEquals('', Bundle::class_prefix(DEFAULT_BUNDLE));
+	}
+
+	/**
+	 * Test the Bundle::path method.
+	 *
+	 * @group laravel
+	 */
+	public function testPathMethodReturnsCorrectPath()
+	{
+		$this->assertEquals(path('app'), Bundle::path(null));
+		$this->assertEquals(path('app'), Bundle::path(DEFAULT_BUNDLE));
+		$this->assertEquals(path('bundle').'dashboard'.DS, Bundle::path('dashboard'));
+	}
+
+	/**
+	 * Test the Bundle::asset method.
+	 *
+	 * @group laravel
+	 */
+	public function testAssetPathReturnsPathToBundlesAssets()
+	{
+		$this->assertEquals('/bundles/dashboard/', Bundle::assets('dashboard'));
+		$this->assertEquals('/', Bundle::assets(DEFAULT_BUNDLE));
+
+		Config::set('application.url', '');
+	}
+
+	/**
+	 * Test the Bundle::name method.
+	 *
+	 * @group laravel
+	 */
+	public function testBundleNameCanBeRetrievedFromIdentifier()
+	{
+		$this->assertEquals(DEFAULT_BUNDLE, Bundle::name('something'));
+		$this->assertEquals(DEFAULT_BUNDLE, Bundle::name('something.else'));
+		$this->assertEquals('bundle', Bundle::name('bundle::something.else'));
+	}
+
+	/**
+	 * Test the Bundle::element method.
+	 *
+	 * @group laravel
+	 */
+	public function testElementCanBeRetrievedFromIdentifier()
+	{
+		$this->assertEquals('something', Bundle::element('something'));
+		$this->assertEquals('something.else', Bundle::element('something.else'));
+		$this->assertEquals('something.else', Bundle::element('bundle::something.else'));
+	}
+
+	/**
+	 * Test the Bundle::identifier method.
+	 *
+	 * @group laravel
+	 */
+	public function testIdentifierCanBeConstructed()
+	{
+		$this->assertEquals('something.else', Bundle::identifier(DEFAULT_BUNDLE, 'something.else'));
+		$this->assertEquals('dashboard::something', Bundle::identifier('dashboard', 'something'));
+		$this->assertEquals('dashboard::something.else', Bundle::identifier('dashboard', 'something.else'));
+	}
+
+	/**
+	 * Test the Bundle::resolve method.
+	 *
+	 * @group laravel
+	 */
+	public function testBundleNamesCanBeResolved()
+	{
+		$this->assertEquals(DEFAULT_BUNDLE, Bundle::resolve('foo'));
+		$this->assertEquals('dashboard', Bundle::resolve('dashboard'));
+	}
+
+	/**
+	 * Test the Bundle::parse method.
+	 *
+	 * @group laravel
+	 */
+	public function testParseMethodReturnsElementAndIdentifier()
+	{
+		$this->assertEquals(array('application', 'something'), Bundle::parse('something'));
+		$this->assertEquals(array('application', 'something.else'), Bundle::parse('something.else'));
+		$this->assertEquals(array('dashboard', 'something'), Bundle::parse('dashboard::something'));
+		$this->assertEquals(array('dashboard', 'something.else'), Bundle::parse('dashboard::something.else'));
+	}
+
+	/**
+	 * Test the Bundle::get method.
+	 *
+	 * @group laravel
+	 */
+	public function testOptionMethodReturnsBundleOption()
+	{
+		$this->assertFalse(Bundle::option('dashboard', 'auto'));
+		$this->assertEquals('dashboard', Bundle::option('dashboard', 'location'));
+	}
+
+	/**
+	 * Test the Bundle::all method.
+	 *
+	 * @group laravel
+	 */
+	public function testAllMethodReturnsBundleArray()
+	{
+		Bundle::register('foo');
+		$this->assertEquals(Bundle::$bundles, Bundle::all());
+		unset(Bundle::$bundles['foo']);
+	}
+
+	/**
+	 * Test the Bundle::names method.
+	 *
+	 * @group laravel
+	 */
+	public function testNamesMethodReturnsBundleNames()
+	{
+		Bundle::register('foo');
+		$this->assertEquals(array('dashboard', 'dummy', 'foo'), Bundle::names());
+		unset(Bundle::$bundles['foo']);
+	}
+
+}

+ 79 - 0
laravel/tests/cases/config.test.php

@@ -0,0 +1,79 @@
+<?php
+
+class ConfigTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Tear down the testing environment.
+	 */
+	public function tearDown()
+	{
+		Config::$items = array();
+		Config::$cache = array();
+	}
+
+	/**
+	 * Test the Config::get method.
+	 *
+	 * @group laravel
+	 */
+	public function testItemsCanBeRetrievedFromConfigFiles()
+	{
+		$this->assertEquals('UTF-8', Config::get('application.encoding'));
+		$this->assertEquals('mysql', Config::get('database.connections.mysql.driver'));
+		$this->assertEquals('dashboard', Config::get('dashboard::meta.bundle'));
+	}
+
+	/**
+	 * Test the Config::has method.
+	 *
+	 * @group laravel
+	 */
+	public function testHasMethodIndicatesIfConfigItemExists()
+	{
+		$this->assertFalse(Config::has('application.foo'));
+		$this->assertTrue(Config::has('application.encoding'));
+	}
+
+	/**
+	 * Test the Config::set method.
+	 *
+	 * @group laravel
+	 */
+	public function testConfigItemsCanBeSet()
+	{
+		Config::set('application.encoding', 'foo');
+		Config::set('dashboard::meta.bundle', 'bar');
+
+		$this->assertEquals('foo', Config::get('application.encoding'));
+		$this->assertEquals('bar', Config::get('dashboard::meta.bundle'));
+	}
+
+	/**
+	 * Test that environment configurations are loaded correctly.
+	 *
+	 * @group laravel
+	 */
+	public function testEnvironmentConfigsOverrideNormalConfigurations()
+	{
+		$_SERVER['LARAVEL_ENV'] = 'local';
+
+		$this->assertEquals('sqlite', Config::get('database.default'));
+
+		unset($_SERVER['LARAVEL_ENV']);
+	}
+
+	/**
+	 * Test that items can be set after the entire file has already been loaded.
+	 *
+	 * @group laravel
+	 */
+	public function testItemsCanBeSetAfterEntireFileIsLoaded()
+	{
+		Config::get('application');
+		Config::set('application.key', 'taylor');
+		$application = Config::get('application');
+
+		$this->assertEquals('taylor', $application['key']);
+	}
+
+}

+ 267 - 0
laravel/tests/cases/controller.test.php

@@ -0,0 +1,267 @@
+<?php
+
+class ControllerTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Setup the testing environment.
+	 */
+	public function setUp()
+	{
+		$_SERVER['REQUEST_METHOD'] = 'GET';
+	}
+
+	/**
+	 * Tear down the testing environment.
+	 */
+	public function tearDown()
+	{
+		unset(Filter::$filters['test-all-before']);
+		unset(Filter::$filters['test-all-after']);
+		unset(Filter::$filters['test-profile-before']);
+		unset($_SERVER['REQUEST_METHOD']);
+	}
+
+	/**
+	 * Test the Controller::call method.
+	 *
+	 * @group laravel
+	 */
+	public function testBasicControllerActionCanBeCalled()
+	{
+		$this->assertEquals('action_index', Controller::call('auth@index')->content);
+		$this->assertEquals('Admin_Panel_Index', Controller::call('admin.panel@index')->content);
+		$this->assertEquals('Taylor', Controller::call('auth@profile', array('Taylor'))->content);
+		$this->assertEquals('Dashboard_Panel_Index', Controller::call('dashboard::panel@index')->content);
+	}
+
+	/**
+	 * Test basic controller filters are called.
+	 *
+	 * @group laravel
+	 */
+	public function testAssignedBeforeFiltersAreRun()
+	{
+		$_SERVER['test-all-after'] = false;
+		$_SERVER['test-all-before'] = false;
+
+		Controller::call('filter@index');
+
+		$this->assertTrue($_SERVER['test-all-after']);
+		$this->assertTrue($_SERVER['test-all-before']);
+	}
+
+	/**
+	 * Test that "only" filters only apply to their assigned methods.
+	 *
+	 * @group laravel
+	 */
+	public function testOnlyFiltersOnlyApplyToTheirAssignedMethods()
+	{
+		$_SERVER['test-profile-before'] = false;
+
+		Controller::call('filter@index');
+
+		$this->assertFalse($_SERVER['test-profile-before']);
+
+		Controller::call('filter@profile');
+
+		$this->assertTrue($_SERVER['test-profile-before']);
+	}
+
+	/**
+	 * Test that "except" filters only apply to the excluded methods.
+	 *
+	 * @group laravel
+	 */
+	public function testExceptFiltersOnlyApplyToTheExlucdedMethods()
+	{
+		$_SERVER['test-except'] = false;
+
+		Controller::call('filter@index');
+		Controller::call('filter@profile');
+
+		$this->assertFalse($_SERVER['test-except']);
+
+		Controller::call('filter@show');
+
+		$this->assertTrue($_SERVER['test-except']);
+	}
+
+	/**
+	 * Test that filters can be constrained by the request method.
+	 *
+	 * @group laravel
+	 */
+	public function testFiltersCanBeConstrainedByRequestMethod()
+	{
+		$_SERVER['test-on-post'] = false;
+
+		Request::$foundation->setMethod('GET');
+		Controller::call('filter@index');
+
+		$this->assertFalse($_SERVER['test-on-post']);
+
+		Request::$foundation->setMethod('POST');
+		Controller::call('filter@index');
+
+		$this->assertTrue($_SERVER['test-on-post']);
+
+		$_SERVER['test-on-get-put'] = false;
+
+		Request::$foundation->setMethod('POST');
+		Controller::call('filter@index');
+
+		$this->assertFalse($_SERVER['test-on-get-put']);
+
+		Request::$foundation->setMethod('PUT');
+		Controller::call('filter@index');
+
+		$this->assertTrue($_SERVER['test-on-get-put']);
+	}
+
+	public function testGlobalBeforeFilterIsNotCalledByController()
+	{
+		$_SERVER['before'] = false;
+		$_SERVER['after'] = false;
+
+		Controller::call('auth@index');
+
+		$this->assertFalse($_SERVER['before']);
+		$this->assertFalse($_SERVER['after']);
+	}
+
+	/**
+	 * Test that before filters can override the controller response.
+	 *
+	 * @group laravel
+	 */
+	public function testBeforeFiltersCanOverrideResponses()
+	{
+		$this->assertEquals('Filtered!', Controller::call('filter@login')->content);
+	}
+
+	/**
+	 * Test that after filters do not affect the response.
+	 *
+	 * @group laravel
+	 */
+	public function testAfterFiltersDoNotAffectControllerResponse()
+	{
+		$this->assertEquals('action_logout', Controller::call('filter@logout')->content);
+	}
+
+	/**
+	 * Test that filter parameters are passed to the filter.
+	 *
+	 * @group laravel
+	 */
+	public function testFilterParametersArePassedToTheFilter()
+	{
+		$this->assertEquals('12', Controller::call('filter@edit')->content);
+	}
+
+	/**
+	 * Test that multiple filters can be assigned to a single method.
+	 *
+	 * @group laravel
+	 */
+	public function testMultipleFiltersCanBeAssignedToAnAction()
+	{
+		$_SERVER['test-multi-1'] = false;
+		$_SERVER['test-multi-2'] = false;
+
+		Controller::call('filter@save');
+
+		$this->assertTrue($_SERVER['test-multi-1']);
+		$this->assertTrue($_SERVER['test-multi-2']);
+	}
+
+	/**
+	 * Test Restful controllers respond by request method.
+	 *
+	 * @group laravel
+	 */
+	public function testRestfulControllersRespondWithRestfulMethods()
+	{
+		Request::$foundation->setMethod('GET');
+		//$_SERVER['REQUEST_METHOD'] = 'GET';
+
+		$this->assertEquals('get_index', Controller::call('restful@index')->content);
+
+		//$_SERVER['REQUEST_METHOD'] = 'PUT';
+		Request::$foundation->setMethod('PUT');
+
+		$this->assertEquals(404, Controller::call('restful@index')->status());
+
+		//$_SERVER['REQUEST_METHOD'] = 'POST';
+		Request::$foundation->setMethod('POST');
+
+		$this->assertEquals('post_index', Controller::call('restful@index')->content);
+	}
+
+	/**
+	 * Test that the template is returned by template controllers.
+	 *
+	 * @group laravel
+	 */
+	public function testTemplateControllersReturnTheTemplate()
+	{
+		$response = Controller::call('template.basic@index');
+
+		$home = file_get_contents(path('app').'views/home/index.php');
+
+		$this->assertEquals($home, $response->content);
+	}
+
+	/**
+	 * Test that controller templates can be named views.
+	 *
+	 * @group laravel
+	 */
+	public function testControllerTemplatesCanBeNamedViews()
+	{
+		View::name('home.index', 'home');
+
+		$response = Controller::call('template.named@index');
+
+		$home = file_get_contents(path('app').'views/home/index.php');
+
+		$this->assertEquals($home, $response->content);
+
+		View::$names = array();
+	}
+
+	/**
+	 * Test that the "layout" method is called on the controller.
+	 *
+	 * @group laravel
+	 */
+	public function testTheTemplateCanBeOverriden()
+	{
+		$this->assertEquals('Layout', Controller::call('template.override@index')->content);
+	}
+
+	/**
+	 * Test the Controller::resolve method.
+	 *
+	 * @group laravel
+	 */
+	public function testResolveMethodChecksTheIoCContainer()
+	{
+		IoC::register('controller: home', function()
+		{
+			require_once path('app').'controllers/home.php';
+
+			$controller = new Home_Controller;
+
+			$controller->foo = 'bar';
+
+			return $controller;
+		});
+
+		$controller = Controller::resolve(DEFAULT_BUNDLE, 'home');
+
+		$this->assertEquals('bar', $controller->foo);
+	}
+
+}

+ 134 - 0
laravel/tests/cases/cookie.test.php

@@ -0,0 +1,134 @@
+<?php namespace Laravel;
+
+use Symfony\Component\HttpFoundation\LaravelRequest as RequestFoundation;
+
+/**
+ * Stub the global setcookie method into the Laravel namespace.
+ */
+function setcookie($name, $value, $time, $path, $domain, $secure)
+{
+	$_SERVER['cookie.stub'][$name] = compact('name', 'value', 'time', 'path', 'domain', 'secure');
+}
+
+function headers_sent()
+{
+	return $_SERVER['function.headers_sent'];
+}
+
+class CookieTest extends \PHPUnit_Framework_TestCase {
+
+	/**
+	 * Setup the test environment.
+	 */
+	public function setUp()
+	{
+		Cookie::$jar = array();
+	}
+
+	/**
+	 * Tear down the test environment.
+	 */
+	public function tearDown()
+	{
+		Cookie::$jar = array();
+	}
+
+	/**
+	 * Set one of the $_SERVER variables.
+	 *
+	 * @param string  $key
+	 * @param string  $value
+	 */
+	protected function setServerVar($key, $value)
+	{
+		$_SERVER[$key] = $value;
+
+		$this->restartRequest();
+	}
+
+	/**
+	 * Reinitialize the global request.
+	 * 
+	 * @return void
+	 */
+	protected function restartRequest()
+	{
+		// FIXME: Ugly hack, but old contents from previous requests seem to
+		// trip up the Foundation class.
+		$_FILES = array();
+
+		Request::$foundation = RequestFoundation::createFromGlobals();
+	}
+
+	/**
+	 * Test Cookie::has method.
+	 *
+	 * @group laravel
+	 */
+	public function testHasMethodIndicatesIfCookieInSet()
+	{
+		Cookie::$jar['foo'] = array('value' => 'bar');
+		$this->assertTrue(Cookie::has('foo'));
+		$this->assertFalse(Cookie::has('bar'));
+
+		Cookie::put('baz', 'foo');
+		$this->assertTrue(Cookie::has('baz'));
+	}
+
+	/**
+	 * Test the Cookie::get method.
+	 *
+	 * @group laravel
+	 */
+	public function testGetMethodCanReturnValueOfCookies()
+	{
+		Cookie::$jar['foo'] = array('value' => 'bar');
+		$this->assertEquals('bar', Cookie::get('foo'));
+
+		Cookie::put('bar', 'baz');
+		$this->assertEquals('baz', Cookie::get('bar'));
+	}
+
+	/**
+	 * Test Cookie::forever method.
+	 *
+	 * @group laravel
+	 */
+	public function testForeverShouldUseATonOfMinutes()
+	{
+		Cookie::forever('foo', 'bar');
+		$this->assertEquals('bar', Cookie::$jar['foo']['value']);
+
+		// Shouldn't be able to test this cause while we indicate -2000 seconds 
+		// cookie expiration store timestamp.
+		// $this->assertEquals(525600, Cookie::$jar['foo']['expiration']);
+
+		$this->setServerVar('HTTPS', 'on');
+
+		Cookie::forever('bar', 'baz', 'path', 'domain', true);
+		$this->assertEquals('path', Cookie::$jar['bar']['path']);
+		$this->assertEquals('domain', Cookie::$jar['bar']['domain']);
+		$this->assertTrue(Cookie::$jar['bar']['secure']);
+
+		$this->setServerVar('HTTPS', 'off');
+	}
+
+	/**
+	 * Test the Cookie::forget method.
+	 *
+	 * @group laravel
+	 */
+	public function testForgetSetsCookieWithExpiration()
+	{
+		Cookie::forget('bar', 'path', 'domain');
+
+		// Shouldn't be able to test this cause while we indicate -2000 seconds 
+		// cookie expiration store timestamp.
+		//$this->assertEquals(-2000, Cookie::$jar['bar']['expiration']);
+
+		$this->assertEquals('path', Cookie::$jar['bar']['path']);
+		$this->assertEquals('domain', Cookie::$jar['bar']['domain']);
+		$this->assertFalse(Cookie::$jar['bar']['secure']);
+	}
+
+}

+ 74 - 0
laravel/tests/cases/database.test.php

@@ -0,0 +1,74 @@
+<?php
+
+class DatabaseTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Set up the test environment.
+	 */
+	public function setUp()
+	{
+		DB::$connections = array();
+	}
+
+	/**
+	 * Tear down the test environment.
+	 */
+	public function tearDown()
+	{
+		DB::$connections = array();
+	}
+
+	/**
+	 * Test the DB::connection method.
+	 *
+	 * @group laravel
+	 */
+	public function testConnectionMethodReturnsConnection()
+	{
+		$connection = DatabaseConnectStub::connection();
+		$this->assertTrue(isset(DB::$connections[Config::get('database.default')]));
+
+		$connection = DatabaseConnectStub::connection('mysql');
+		$this->assertTrue(isset(DB::$connections['mysql']));
+		$this->assertEquals(DB::$connections['mysql']->pdo->laravel_config, Config::get('database.connections.mysql'));
+	}
+
+	/**
+	 * Test the DB::profile method.
+	 *
+	 * @group laravel
+	 */
+	public function testProfileMethodReturnsQueries()
+	{
+		Laravel\Database\Connection::$queries = array('Taylor');
+		$this->assertEquals(array('Taylor'), DB::profile());
+		Laravel\Database\Connection::$queries = array();
+	}
+
+	/**
+	 * Test the __callStatic method.
+	 *
+	 * @group laravel
+	 */
+	public function testConnectionMethodsCanBeCalledStaticly()
+	{
+		$this->assertEquals('sqlite', DB::driver());
+	}
+
+}
+
+class DatabaseConnectStub extends Laravel\Database {
+
+	protected static function connect($config) { return new PDOStub($config); }
+
+}
+
+class PDOStub extends PDO {
+	
+	public $laravel_config;
+
+	public function __construct($config) { $this->laravel_config = $config; }
+
+	public function foo() { return 'foo'; }
+
+}

+ 43 - 0
laravel/tests/cases/event.test.php

@@ -0,0 +1,43 @@
+<?php
+
+class EventTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Tear down the testing environment.
+	 */
+	public function tearDown()
+	{
+		unset(Event::$events['test.event']);
+	}
+
+	/**
+	 * Test basic event firing.
+	 *
+	 * @group laravel
+	 */
+	public function testListenersAreFiredForEvents()
+	{
+		Event::listen('test.event', function() { return 1; });
+		Event::listen('test.event', function() { return 2; });
+
+		$responses = Event::fire('test.event');
+
+		$this->assertEquals(1, $responses[0]);
+		$this->assertEquals(2, $responses[1]);
+	}
+
+	/**
+	 * Test parameters can be passed to event listeners.
+	 *
+	 * @group laravel
+	 */
+	public function testParametersCanBePassedToEvents()
+	{
+		Event::listen('test.event', function($var) { return $var; });
+
+		$responses = Event::fire('test.event', array('Taylor'));
+
+		$this->assertEquals('Taylor', $responses[0]);
+	}
+
+}

+ 50 - 0
laravel/tests/cases/fluent.test.php

@@ -0,0 +1,50 @@
+<?php
+
+use Laravel\Fluent;
+
+class FluentTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Test the Fluent constructor.
+	 *
+	 * @group laravel
+	 */
+	public function testAttributesAreSetByConstructor()
+	{
+		$array = array('name' => 'Taylor', 'age' => 25);
+
+		$fluent = new Fluent($array);
+
+		$this->assertEquals($array, $fluent->attributes);
+	}
+
+	/**
+	 * Test the Fluent::get method.
+	 *
+	 * @group laravel
+	 */
+	public function testGetMethodReturnsAttribute()
+	{
+		$fluent = new Fluent(array('name' => 'Taylor'));
+
+		$this->assertEquals('Taylor', $fluent->get('name'));
+		$this->assertEquals('Default', $fluent->get('foo', 'Default'));
+		$this->assertEquals('Taylor', $fluent->name);
+		$this->assertNull($fluent->foo);
+	}
+
+	public function testMagicMethodsCanBeUsedToSetAttributes()
+	{
+		$fluent = new Fluent;
+
+		$fluent->name = 'Taylor';
+		$fluent->developer();
+		$fluent->age(25);
+
+		$this->assertEquals('Taylor', $fluent->name);
+		$this->assertTrue($fluent->developer);
+		$this->assertEquals(25, $fluent->age);
+		$this->assertInstanceOf('Laravel\\Fluent', $fluent->programmer());
+	}
+
+}

+ 37 - 0
laravel/tests/cases/hash.test.php

@@ -0,0 +1,37 @@
+<?php
+
+class HashTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Test the Hash::make method.
+	 *
+	 * @group laravel
+	 */
+	public function testHashProducesValidBcryptHash()
+	{
+		$this->assertTrue(strlen(Hash::make('taylor')) == 60);
+	}
+
+	/**
+	 * Test the Hash::check method.
+	 *
+	 * @group laravel
+	 */
+	public function testHashCheckFailsWhenNotMatching()
+	{
+		$hash = Hash::make('taylor');
+
+		$this->assertFalse(Hash::check('foo', $hash));
+	}
+
+	/**
+	 * Test the Hash::check method.
+	 *
+	 * @group laravel
+	 */
+	public function testHashCheckPassesWhenMatches()
+	{
+		$this->assertTrue(Hash::check('taylor', Hash::make('taylor')));
+	}
+
+}

+ 174 - 0
laravel/tests/cases/input.test.php

@@ -0,0 +1,174 @@
+<?php
+
+class InputTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Setup the testing environment.
+	 */
+	public function setUp()
+	{
+		Config::set('application.key', 'foo');
+	}
+
+	/**
+	 * Tear down the testing environemnt.
+	 */
+	public function tearDown()
+	{
+		// @todo clear httpfoundation request data
+		Config::set('application.key', '');
+		Session::$instance = null;
+	}
+
+	/**
+	 * Test the Input::all method.
+	 *
+	 * @group laravel
+	 */
+	public function testAllMethodReturnsInputAndFiles()
+	{
+		Request::foundation()->request->add(array('name' => 'Taylor'));
+		
+		$_FILES = array('age' => 25);
+
+		$this->assertEquals(Input::all(), array('name' => 'Taylor', 'age' => 25));
+	}
+
+	/**
+	 * Test the Input::has method.
+	 *
+	 * @group laravel
+	 */
+	public function testHasMethodIndicatesTheExistenceOfInput()
+	{
+		$this->assertFalse(Input::has('foo'));
+
+		Request::foundation()->request->add(array('name' => 'Taylor'));
+
+		$this->assertTrue(Input::has('name'));
+	}
+
+	/**
+	 * Test the Input::get method.
+	 *
+	 * @group laravel
+	 */
+	public function testGetMethodReturnsInputValue()
+	{
+		Request::foundation()->request->add(array('name' => 'Taylor'));
+
+		$this->assertEquals('Taylor', Input::get('name'));
+		$this->assertEquals('Default', Input::get('foo', 'Default'));
+	}
+
+	/**
+	 * Test the Input::only method.
+	 *
+	 * @group laravel
+	 */
+	public function testOnlyMethodReturnsSubsetOfInput()
+	{
+		Request::foundation()->request->add(array('name' => 'Taylor', 'age' => 25));
+
+		$this->assertEquals(array('name' => 'Taylor'), Input::only(array('name')));
+	}
+
+	/**
+	 * Test the Input::except method.
+	 *
+	 * @group laravel
+	 */
+	public function testExceptMethodReturnsSubsetOfInput()
+	{
+		Request::foundation()->request->add(array('name' => 'Taylor', 'age' => 25));
+
+		$this->assertEquals(array('age' => 25), Input::except(array('name')));
+	}
+
+	/**
+	 * Test the Input::old method.
+	 *
+	 * @group laravel
+	 */
+	public function testOldInputCanBeRetrievedFromSession()
+	{
+		$this->setSession();
+
+		Session::$instance->session['data']['laravel_old_input'] = array('name' => 'Taylor');
+
+		$this->assertNull(Input::old('foo'));
+		$this->assertTrue(Input::had('name'));
+		$this->assertFalse(Input::had('foo'));
+		$this->assertEquals('Taylor', Input::old('name'));
+	}
+
+	/**
+	 * Test the Input::file method.
+	 *
+	 * @group laravel
+	 */
+	public function testFileMethodReturnsFromFileArray()
+	{
+		$_FILES['foo'] = array('name' => 'Taylor', 'size' => 100);
+
+		$this->assertEquals('Taylor', Input::file('foo.name'));
+		$this->assertEquals(array('name' => 'Taylor', 'size' => 100), Input::file('foo'));
+	}
+
+	/**
+	 * Test the Input::flash method.
+	 *
+	 * @group laravel
+	 */
+	public function testFlashMethodFlashesInputToSession()
+	{
+		$this->setSession();
+
+		$input = array('name' => 'Taylor', 'age' => 25);
+		Request::foundation()->request->add($input);
+
+		Input::flash();
+
+		$this->assertEquals($input, Session::$instance->session['data'][':new:']['laravel_old_input']);
+
+		Input::flash('only', array('name'));
+
+		$this->assertEquals(array('name' => 'Taylor'), Session::$instance->session['data'][':new:']['laravel_old_input']);
+
+		Input::flash('except', array('name'));
+
+		$this->assertEquals(array('age' => 25), Session::$instance->session['data'][':new:']['laravel_old_input']);
+	}
+
+	/**
+	 * Test the Input::flush method.
+	 *
+	 * @group laravel
+	 */
+	public function testFlushMethodClearsFlashedInput()
+	{
+		$this->setSession();
+
+		$input = array('name' => 'Taylor', 'age' => 30);
+		Request::foundation()->request->add($input);
+
+		Input::flash();
+
+		$this->assertEquals($input, Session::$instance->session['data'][':new:']['laravel_old_input']);
+
+		Input::flush();
+
+		$this->assertEquals(array(), Session::$instance->session['data'][':new:']['laravel_old_input']);
+	}
+
+	/**
+	 * Set the session payload instance.
+	 */
+	protected function setSession()
+	{
+		$driver = $this->getMock('Laravel\\Session\\Drivers\\Driver');
+
+		Session::$instance = new Laravel\Session\Payload($driver);
+	}
+
+}

+ 74 - 0
laravel/tests/cases/ioc.test.php

@@ -0,0 +1,74 @@
+<?php
+
+class IoCTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Test IoC::register and IoC::resolve.
+	 *
+	 * @group laravel
+	 */
+	public function testRegisteredClassCanBeResolved()
+	{
+		IoC::register('foo', function()
+		{
+			return 'Taylor';
+		});
+
+		$this->assertEquals('Taylor', IoC::resolve('foo'));
+	}
+
+	/**
+	 * Test that singletons are created once.
+	 *
+	 * @group laravel
+	 */
+	public function testSingletonsAreCreatedOnce()
+	{
+		IoC::singleton('foo', function()
+		{
+			return new StdClass;
+		});
+
+		$object = IoC::resolve('foo');
+
+		$this->assertTrue($object === IoC::resolve('foo'));
+	}
+
+	/**
+	 * Test the IoC::instance method.
+	 *
+	 * @group laravel
+	 */
+	public function testInstancesAreReturnedBySingleton()
+	{
+		$object = new StdClass;
+
+		IoC::instance('bar', $object);
+
+		$this->assertTrue($object === IoC::resolve('bar'));
+	}
+
+	/**
+	 * Test the IoC::registered method.
+	 */
+	public function testRegisteredMethodIndicatesIfRegistered()
+	{
+		IoC::register('foo', function() {});
+
+		$this->assertTrue(IoC::registered('foo'));
+		$this->assertFalse(IoC::registered('baz'));
+	}
+
+	/**
+	 * Test the IoC::controller method.
+	 *
+	 * @group laravel
+	 */
+	public function testControllerMethodRegistersAController()
+	{
+		IoC::register('controller: ioc.test', function() {});
+
+		$this->assertTrue(IoC::registered('controller: ioc.test'));
+	}
+
+}

+ 68 - 0
laravel/tests/cases/lang.test.php

@@ -0,0 +1,68 @@
+<?php
+
+class LangTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Test the Lang::line method.
+	 *
+	 * @group laravel
+	 */
+	public function testGetMethodCanGetFromDefaultLanguage()
+	{
+		$validation = require path('app').'language/en/validation.php';
+
+		$this->assertEquals($validation['required'], Lang::line('validation.required')->get());
+		$this->assertEquals('Taylor', Lang::line('validation.foo')->get(null, 'Taylor'));
+	}
+
+	/**
+	 * Test the Lang::line method.
+	 *
+	 * @group laravel
+	 */
+	public function testGetMethodCanGetLinesForAGivenLanguage()
+	{
+		$validation = require path('app').'language/sp/validation.php';
+
+		$this->assertEquals($validation['required'], Lang::line('validation.required')->get('sp'));
+	}
+
+	/**
+	 * Test the __toString method.
+	 *
+	 * @group laravel
+	 */
+	public function testLineCanBeCastAsString()
+	{
+		$validation = require path('app').'language/en/validation.php';
+
+		$this->assertEquals($validation['required'], (string) Lang::line('validation.required'));
+	}
+
+	/**
+	 * Test that string replacements are made on lines.
+	 *
+	 * @group laravel
+	 */
+	public function testReplacementsAreMadeOnLines()
+	{
+		$validation = require path('app').'language/en/validation.php';
+
+		$line = str_replace(':attribute', 'e-mail', $validation['required']);
+
+		$this->assertEquals($line, Lang::line('validation.required', array('attribute' => 'e-mail'))->get());
+	}
+
+	/**
+	 * Test the Lang::has method.
+	 *
+	 * @group laravel
+	 */
+	public function testHasMethodIndicatesIfLangaugeLineExists()
+	{
+		$this->assertTrue(Lang::has('validation'));
+		$this->assertTrue(Lang::has('validation.required'));
+		$this->assertFalse(Lang::has('validation.foo'));
+	}
+
+}

+ 115 - 0
laravel/tests/cases/messages.test.php

@@ -0,0 +1,115 @@
+<?php
+
+class MessagesTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * The Messages instance.
+	 *
+	 * @var Messages
+	 */
+	public $messages;
+
+	/**
+	 * Setup the test environment.
+	 */
+	public function setUp()
+	{
+		$this->messages = new Laravel\Messages;
+	}
+
+	/**
+	 * Test the Messages::add method.
+	 *
+	 * @group laravel
+	 */
+	public function testAddingMessagesDoesNotCreateDuplicateMessages()
+	{
+		$this->messages->add('email', 'test');
+		$this->messages->add('email', 'test');
+		$this->assertCount(1, $this->messages->messages);
+	}
+
+	/**
+	 * Test the Messages::add method.
+	 *
+	 * @group laravel
+	 */
+	public function testAddMethodPutsMessageInMessagesArray()
+	{
+		$this->messages->add('email', 'test');
+		$this->assertArrayHasKey('email', $this->messages->messages);
+		$this->assertEquals('test', $this->messages->messages['email'][0]);
+	}
+
+	/**
+	 * Test the Messages::has method.
+	 *
+	 * @group laravel
+	 */
+	public function testHasMethodReturnsTrue()
+	{
+		$this->messages->add('email', 'test');
+		$this->assertTrue($this->messages->has('email'));
+	}
+
+	/**
+	 * Test the Messages::has method.
+	 *
+	 * @group laravel
+	 */
+	public function testHasMethodReturnsFalse()
+	{
+		$this->assertFalse($this->messages->has('something'));
+	}
+
+	/**
+	 * Test the Messages::first method.
+	 *
+	 * @group laravel
+	 */
+	public function testFirstMethodReturnsSingleString()
+	{
+		$this->messages->add('email', 'test');
+		$this->assertEquals('test', $this->messages->first('email'));
+		$this->assertEquals('', $this->messages->first('something'));
+	}
+
+	/**
+	 * Test the Messages::get method.
+	 *
+	 * @group laravel
+	 */
+	public function testGetMethodReturnsAllMessagesForAttribute()
+	{
+		$messages = array('email' => array('something', 'else'));
+		$this->messages->messages = $messages;
+		$this->assertEquals(array('something', 'else'), $this->messages->get('email'));
+	}
+
+	/**
+	 * Test the Messages::all method.
+	 *
+	 * @group laravel
+	 */
+	public function testAllMethodReturnsAllErrorMessages()
+	{
+		$messages = array('email' => array('something', 'else'), 'name' => array('foo'));
+		$this->messages->messages = $messages;
+		$this->assertEquals(array('something', 'else', 'foo'), $this->messages->all());
+	}
+
+	/**
+	 * Test the Messages::get method.
+	 *
+	 * @group laravel
+	 */
+	public function testMessagesRespectFormat()
+	{
+		$this->messages->add('email', 'test');
+		$this->assertEquals('<p>test</p>', $this->messages->first('email', '<p>:message</p>'));
+		$this->assertEquals(array('<p>test</p>'), $this->messages->get('email', '<p>:message</p>'));
+		$this->assertEquals(array('<p>test</p>'), $this->messages->all('<p>:message</p>'));
+	}
+
+
+}

+ 48 - 0
laravel/tests/cases/query.test.php

@@ -0,0 +1,48 @@
+<?php
+
+class QueryTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Test the "find" method.
+	 *
+	 * @group laravel
+	 */
+	public function testFindMethodCanReturnByID()
+	{
+		$this->assertEquals('taylor@example.com', $this->query()->find(1)->email);
+	}
+
+	/**
+	 * Test the select method.
+	 *
+	 * @group laravel
+	 */
+	public function testSelectMethodLimitsColumns()
+	{
+		$result = $this->query()->select(array('email'))->first();
+
+		$this->assertTrue(isset($result->email));
+		$this->assertFalse(isset($result->name));
+	}
+
+	/**
+	 * Test the raw_where method.
+	 *
+	 * @group laravel
+	 */
+	public function testRawWhereCanBeUsed()
+	{
+		
+	}
+
+	/**
+	 * Get the query instance for the test case.
+	 *
+	 * @return Query
+	 */
+	protected function query()
+	{
+		return DB::table('query_test');
+	}
+
+}

+ 143 - 0
laravel/tests/cases/redirect.test.php

@@ -0,0 +1,143 @@
+<?php
+
+use Laravel\Routing\Router;
+
+class RedirectTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Setup the test environment.
+	 */
+	public function setUp()
+	{
+		Config::set('session.driver', 'foo');
+		Router::$routes = array();
+		Router::$names = array();
+		URL::$base = 'http://localhost/';
+		Config::set('application.index', '');
+	}
+
+	/**
+	 * Destroy the test environment.
+	 */
+	public function tearDown()
+	{
+		// @todo clear httpfoundation request data
+		Config::set('session.driver', '');
+		Router::$routes = array();
+		Router::$names = array();
+		URL::$base = '';
+		Config::set('application.index', 'index.php');
+		Session::$instance = null;
+	}
+
+	/**
+	 * Test the Redirect::to method.
+	 *
+	 * @group laravel
+	 */
+	public function testSimpleRedirectSetsCorrectHeaders()
+	{
+		$redirect = Redirect::to('user/profile');
+
+		$this->assertEquals(302, $redirect->status());
+		$this->assertEquals('http://localhost/user/profile', $redirect->headers()->get('location'));
+
+		$redirect = Redirect::to('user/profile', 301, true);
+
+		$this->assertEquals(301, $redirect->status());
+		$this->assertEquals('https://localhost/user/profile', $redirect->headers()->get('location'));
+
+		$redirect = Redirect::to_secure('user/profile', 301);
+
+		$this->assertEquals(301, $redirect->status());
+		$this->assertEquals('https://localhost/user/profile', $redirect->headers()->get('location'));
+	}
+
+	/**
+	 * Test the Redirect::to_route method.
+	 *
+	 * @group laravel
+	 */
+	public function testRedirectsCanBeGeneratedForNamedRoutes()
+	{
+		Route::get('redirect', array('as' => 'redirect'));
+		Route::get('redirect/(:any)/(:any)', array('as' => 'redirect-2'));
+		Route::get('secure/redirect', array('https' => true, 'as' => 'redirect-3'));
+
+		$this->assertEquals(301, Redirect::to_route('redirect', array(), 301, true)->status());
+		$this->assertEquals('http://localhost/redirect', Redirect::to_route('redirect')->headers()->get('location'));
+		$this->assertEquals('https://localhost/secure/redirect', Redirect::to_route('redirect-3', array(), 302)->headers()->get('location'));
+		$this->assertEquals('http://localhost/redirect/1/2', Redirect::to_route('redirect-2', array('1', '2'))->headers()->get('location'));
+	}
+
+	/**
+	 * Test the Redirect::with method.
+	 *
+	 * @group laravel
+	 */
+	public function testWithMethodFlashesItemToSession()
+	{
+		$this->setSession();
+
+		$redirect = Redirect::to('')->with('name', 'Taylor');
+
+		$this->assertEquals('Taylor', Session::$instance->session['data'][':new:']['name']);
+	}
+
+	/**
+	 * Test the Redirect::with_input function.
+	 *
+	 * @group laravel
+	 */
+	public function testWithInputMethodFlashesInputToTheSession()
+	{
+		$this->setSession();
+
+		$input = array('name' => 'Taylor', 'age' => 25);
+		Request::foundation()->request->add($input);
+
+		$redirect = Redirect::to('')->with_input();
+
+		$this->assertEquals($input, Session::$instance->session['data'][':new:']['laravel_old_input']);
+
+		$redirect = Redirect::to('')->with_input('only', array('name'));
+
+		$this->assertEquals(array('name' => 'Taylor'), Session::$instance->session['data'][':new:']['laravel_old_input']);
+
+		$redirect = Redirect::to('')->with_input('except', array('name'));
+
+		$this->assertEquals(array('age' => 25), Session::$instance->session['data'][':new:']['laravel_old_input']);
+	}
+
+	/**
+	 * Test the Redirect::with_errors method.
+	 *
+	 * @group laravel
+	 */
+	public function testWithErrorsFlashesErrorsToTheSession()
+	{
+		$this->setSession();
+
+		Redirect::to('')->with_errors(array('name' => 'Taylor'));
+
+		$this->assertEquals(array('name' => 'Taylor'), Session::$instance->session['data'][':new:']['errors']);
+
+		$validator = Validator::make(array(), array());
+		$validator->errors = array('name' => 'Taylor');
+
+		Redirect::to('')->with_errors($validator);
+
+		$this->assertEquals(array('name' => 'Taylor'), Session::$instance->session['data'][':new:']['errors']);
+	}
+
+	/**
+	 * Set the session payload instance.
+	 */
+	protected function setSession()
+	{
+		$driver = $this->getMock('Laravel\\Session\\Drivers\\Driver');
+
+		Session::$instance = new Laravel\Session\Payload($driver);
+	}
+
+}

+ 177 - 0
laravel/tests/cases/request.test.php

@@ -0,0 +1,177 @@
+<?php
+
+use Symfony\Component\HttpFoundation\LaravelRequest as RequestFoundation;
+
+class SessionPayloadTokenStub {
+
+	public function token() { return 'Taylor'; }
+
+}
+
+class RequestTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Tear down the test environment.
+	 */
+	public function tearDown()
+	{
+		$_POST = array();
+		$_SERVER = array();
+		Request::$route = null;
+		Session::$instance = null;
+	}
+
+	/**
+	 * Set one of the $_SERVER variables.
+	 *
+	 * @param string  $key
+	 * @param string  $value
+	 */
+	protected function setServerVar($key, $value)
+	{
+		$_SERVER[$key] = $value;
+
+		$this->restartRequest();
+	}
+
+	/**
+	 * Set one of the $_POST variables.
+	 *
+	 * @param string  $key
+	 * @param string  $value
+	 */
+	protected function setPostVar($key, $value)
+	{
+		$_POST[$key] = $value;
+
+		$this->restartRequest();
+	}
+
+	/**
+	 * Reinitialize the global request.
+	 * 
+	 * @return void
+	 */
+	protected function restartRequest()
+	{
+		// FIXME: Ugly hack, but old contents from previous requests seem to
+		// trip up the Foundation class.
+		$_FILES = array();
+
+		Request::$foundation = RequestFoundation::createFromGlobals();
+	}
+
+	/**
+	 * Test the Request::method method.
+	 *
+	 * @group laravel
+	 */
+	public function testMethodReturnsTheHTTPRequestMethod()
+	{
+		$this->setServerVar('REQUEST_METHOD', 'POST');
+
+		$this->assertEquals('POST', Request::method());
+
+		$this->setPostVar(Request::spoofer, 'PUT');
+
+		$this->assertEquals('PUT', Request::method());
+	}
+
+	/**
+	 * Test the Request::server method.
+	 *
+	 * @group laravel
+	 */
+	public function testServerMethodReturnsFromServerArray()
+	{
+		$this->setServerVar('TEST', 'something');
+		$this->setServerVar('USER', array('NAME' => 'taylor'));
+
+		$this->assertEquals('something', Request::server('test'));
+		$this->assertEquals('taylor', Request::server('user.name'));
+	}
+
+	/**
+	 * Test the Request::ip method.
+	 *
+	 * @group laravel
+	 */
+	public function testIPMethodReturnsClientIPAddress()
+	{
+		$this->setServerVar('REMOTE_ADDR', 'something');
+		$this->assertEquals('something', Request::ip());
+
+		$this->setServerVar('HTTP_CLIENT_IP', 'something');
+		$this->assertEquals('something', Request::ip());
+
+		$this->setServerVar('HTTP_CLIENT_IP', 'something');
+		$this->assertEquals('something', Request::ip());
+
+		$_SERVER = array();
+		$this->restartRequest();
+		$this->assertEquals('0.0.0.0', Request::ip());
+	}
+
+	/**
+	 * Test the Request::secure method.
+	 *
+	 * @group laravel
+	 */
+	public function testSecureMethodsIndicatesIfHTTPS()
+	{
+		$this->setServerVar('HTTPS', 'on');
+		
+		$this->assertTrue(Request::secure());
+
+		$this->setServerVar('HTTPS', 'off');
+
+		$this->assertFalse(Request::secure());
+	}
+
+	/**
+	 * Test the Request::ajax method.
+	 *
+	 * @group laravel
+	 */
+	public function testAjaxMethodIndicatesWhenAjax()
+	{
+		$this->assertFalse(Request::ajax());
+
+		$this->setServerVar('HTTP_X_REQUESTED_WITH', 'XMLHttpRequest');
+
+		$this->assertTrue(Request::ajax());
+	}
+
+	/**
+	 * Test the Request::forged method.
+	 *
+	 * @group laravel
+	 */
+	public function testForgedMethodIndicatesIfRequestWasForged()
+	{
+		Session::$instance = new SessionPayloadTokenStub;
+
+		$input = array(Session::csrf_token => 'Foo');
+		Request::foundation()->request->add($input);
+
+		$this->assertTrue(Request::forged());
+
+		$input = array(Session::csrf_token => 'Taylor');
+		Request::foundation()->request->add($input);
+		
+		$this->assertFalse(Request::forged());
+	}
+
+	/**
+	 * Test the Request::route method.
+	 *
+	 * @group laravel
+	 */
+	public function testRouteMethodReturnsStaticRoute()
+	{
+		Request::$route = 'Taylor';
+
+		$this->assertEquals('Taylor', Request::route());
+	}
+
+}

+ 89 - 0
laravel/tests/cases/response.test.php

@@ -0,0 +1,89 @@
+<?php
+
+class ResponseTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Test the Response::make method.
+	 *
+	 * @group laravel
+	 */
+	public function testMakeMethodProperlySetsContent()
+	{
+		$response = Response::make('foo', 201, array('bar' => 'baz'));
+
+		$this->assertEquals('foo', $response->content);
+		$this->assertEquals(201, $response->status());
+		$this->assertArrayHasKey('bar', $response->headers()->all());
+		$this->assertEquals('baz', $response->headers()->get('bar'));
+	}
+
+	/**
+	 * Test the Response::view method.
+	 *
+	 * @group laravel
+	 */
+	public function testViewMethodSetsContentToView()
+	{
+		$response = Response::view('home.index', array('name' => 'Taylor'));
+
+		$this->assertEquals('home.index', $response->content->view);
+		$this->assertEquals('Taylor', $response->content->data['name']);
+	}
+
+	/**
+	 * Test the Response::error method.
+	 *
+	 * @group laravel
+	 */
+	public function testErrorMethodSetsContentToErrorView()
+	{
+		$response = Response::error('404', array('name' => 'Taylor'));
+
+		$this->assertEquals(404, $response->status());
+		$this->assertEquals('error.404', $response->content->view);
+		$this->assertEquals('Taylor', $response->content->data['name']);
+	}
+
+	/**
+	 * Test the Response::prepare method.
+	 *
+	 * @group laravel
+	 */
+	public function testPrepareMethodCreatesAResponseInstanceFromGivenValue()
+	{
+		$response = Response::prepare('Taylor');
+
+		$this->assertInstanceOf('Laravel\\Response', $response);
+		$this->assertEquals('Taylor', $response->content);
+
+		$response = Response::prepare(new Response('Taylor'));
+
+		$this->assertInstanceOf('Laravel\\Response', $response);
+		$this->assertEquals('Taylor', $response->content);
+	}
+
+	/**
+	 * Test the Response::header method.
+	 *
+	 * @group laravel
+	 */
+	public function testHeaderMethodSetsValueInHeaderArray()
+	{
+		$response = Response::make('')->header('foo', 'bar');
+
+		$this->assertEquals('bar', $response->headers()->get('foo'));
+	}
+
+	/**
+	 * Test the Response::status method.
+	 *
+	 * @group laravel
+	 */
+	public function testStatusMethodSetsStatusCode()
+	{
+		$response = Response::make('')->status(404);
+
+		$this->assertEquals(404, $response->status());
+	}
+
+}

+ 179 - 0
laravel/tests/cases/route.test.php

@@ -0,0 +1,179 @@
+<?php
+
+use Laravel\Routing\Route;
+
+class RouteTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Tear down the testing environment.
+	 */
+	public static function tearDownAfterClass()
+	{
+		unset($_SERVER['REQUEST_METHOD']);
+		unset(Filter::$filters['test-after']);
+		unset(Filter::$filters['test-before']);
+		unset(Filter::$filters['test-params']);
+		unset(Filter::$filters['test-multi-1']);
+		unset(Filter::$filters['test-multi-2']);
+	}
+
+	/**
+	 * Destroy the testing environment.
+	 */
+	public function tearDown()
+	{
+		Request::$route = null;
+	}
+
+	/**
+	 * Tests the Route::is method.
+	 *
+	 * @group laravel
+	 */
+	public function testIsMethodIndicatesIfTheRouteHasAGivenName()
+	{
+		$route = new Route('GET', '/', array('as' => 'profile'));
+		$this->assertTrue($route->is('profile'));
+		$this->assertFalse($route->is('something'));
+	}
+
+	/**
+	 * Test the basic execution of a route.
+	 *
+	 * @group laravel
+	 */
+	public function testBasicRoutesCanBeExecutedProperly()
+	{
+		$route = new Route('GET', '', array(function() { return 'Route!'; }));
+
+		$this->assertEquals('Route!', $route->call()->content);
+		$this->assertInstanceOf('Laravel\\Response', $route->call());
+	}
+
+	/**
+	 * Test that route parameters are passed into the handlers.
+	 *
+	 * @group laravel
+	 */
+	public function testRouteParametersArePassedIntoTheHandler()
+	{
+		$route = new Route('GET', '', array(function($var) { return $var; }), array('Taylor'));
+
+		$this->assertEquals('Taylor', $route->call()->content);
+		$this->assertInstanceOf('Laravel\\Response', $route->call());
+	}
+
+	/**
+	 * Test that calling a route calls the global before and after filters.
+	 *
+	 * @group laravel
+	 */
+	public function testCallingARouteCallsTheBeforeAndAfterFilters()
+	{
+		$route = new Route('GET', '', array(function() { return 'Hi!'; }));
+
+		$_SERVER['before'] = false;
+		$_SERVER['after'] = false;
+
+		$route->call();
+
+		$this->assertTrue($_SERVER['before']);
+		$this->assertTrue($_SERVER['after']);
+	}
+
+	/**
+	 * Test that before filters override the route response.
+	 *
+	 * @group laravel
+	 */
+	public function testBeforeFiltersOverrideTheRouteResponse()
+	{
+		Filter::register('test-before', function()
+		{
+			return 'Filtered!';
+		});
+
+		$route = new Route('GET', '', array('before' => 'test-before', function() {
+			return 'Route!';
+		}));
+
+		$this->assertEquals('Filtered!', $route->call()->content);
+	}
+
+	/**
+	 * Test that after filters do not affect the route response.
+	 *
+	 * @group laravel
+	 */
+	public function testAfterFilterDoesNotAffectTheResponse()
+	{
+		$_SERVER['test-after'] = false;
+
+		Filter::register('test-after', function()
+		{
+			$_SERVER['test-after'] = true;
+			return 'Filtered!';
+		});
+
+		$route = new Route('GET', '', array('after' => 'test-after', function()
+		{
+			return 'Route!';
+		}));
+
+		$this->assertEquals('Route!', $route->call()->content);
+		$this->assertTrue($_SERVER['test-after']);
+	}
+
+	/**
+	 * Test that the route calls the appropriate controller method when delegating.
+	 *
+	 * @group laravel
+	 */
+	public function testControllerActionCalledWhenDelegating()
+	{
+		$_SERVER['REQUEST_METHOD'] = 'GET';
+
+		$route = new Route('GET', '', array('uses' => 'auth@index'));
+
+		$this->assertEquals('action_index', $route->call()->content);
+	}
+
+	/**
+	 * Test that filter parameters are passed to the filter.
+	 *
+	 * @group laravel
+	 */
+	public function testFilterParametersArePassedToFilter()
+	{
+		Filter::register('test-params', function($var1, $var2)
+		{
+			return $var1.$var2;
+		});
+
+		$route = new Route('GET', '', array('before' => 'test-params:1,2'));
+
+		$this->assertEquals('12', $route->call()->content);
+	}
+
+	/**
+	 * Test that multiple filters can be assigned to a route.
+	 *
+	 * @group laravel
+	 */
+	public function testMultipleFiltersCanBeAssignedToARoute()
+	{
+		$_SERVER['test-multi-1'] = false;
+		$_SERVER['test-multi-2'] = false;
+
+		Filter::register('test-multi-1', function() { $_SERVER['test-multi-1'] = true; });
+		Filter::register('test-multi-2', function() { $_SERVER['test-multi-2'] = true; });
+
+		$route = new Route('GET', '', array('before' => 'test-multi-1|test-multi-2'));
+
+		$route->call();
+
+		$this->assertTrue($_SERVER['test-multi-1']);
+		$this->assertTrue($_SERVER['test-multi-2']);
+	}
+
+}

+ 160 - 0
laravel/tests/cases/routing.test.php

@@ -0,0 +1,160 @@
+<?php
+
+use Laravel\Routing\Router;
+
+class RoutingTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Destroy the testing environment.
+	 */
+	public function setUp()
+	{
+		Bundle::$started = array();
+		Bundle::$routed = array();
+		Router::$names = array();
+		Router::$routes = array();
+	}
+
+	/**
+	 * Destroy the testing environment.
+	 */
+	public function tearDown()
+	{
+		Bundle::$started = array();
+		Bundle::$routed = array();
+		Router::$names = array();
+		Router::$routes = array();
+	}
+
+	/**
+	 * Test the Router::find method.
+	 *
+	 * @group laravel
+	 */
+	public function testNamedRoutesCanBeLocatedByTheRouter()
+	{
+		Route::get('/', array('as' => 'home'));
+		Route::get('dashboard', array('as' => 'dashboard'));
+
+		$home = Router::find('home');
+		$dashboard = Router::find('dashboard');
+
+		$this->assertTrue(isset($home['/']));
+		$this->assertTrue(isset($dashboard['dashboard']));
+	}
+
+	/**
+	 * Test the basic routing mechanism.
+	 *
+	 * @group laravel
+	 */
+	public function testBasicRouteCanBeRouted()
+	{
+		Route::get('/', function() {});
+		Route::get('home, main', function() {});
+
+		$this->assertEquals('/', Router::route('GET', '/')->uri);
+		$this->assertEquals('home', Router::route('GET', 'home')->uri);
+		$this->assertEquals('main', Router::route('GET', 'main')->uri);
+	}
+
+	/**
+	 * Test that the router can handle basic wildcards.
+	 *
+	 * @group laravel
+	 */
+	public function testWildcardRoutesCanBeRouted()
+	{
+		Route::get('user/(:num)', function() {});
+		Route::get('profile/(:any)/(:num)', function() {});
+
+		$this->assertNull(Router::route('GET', 'user/1.5'));
+		$this->assertNull(Router::route('GET', 'user/taylor'));
+		$this->assertEquals(array(25), Router::route('GET', 'user/25')->parameters);
+		$this->assertEquals('user/(:num)', Router::route('GET', 'user/1')->uri);
+
+		$this->assertNull(Router::route('GET', 'profile/1/otwell'));
+		$this->assertNull(Router::route('POST', 'profile/taylor/1'));
+		$this->assertNull(Router::route('GET', 'profile/taylor/otwell'));
+		$this->assertNull(Router::route('GET', 'profile/taylor/1/otwell'));
+		$this->assertEquals(array('taylor', 25), Router::route('GET', 'profile/taylor/25')->parameters);
+		$this->assertEquals('profile/(:any)/(:num)', Router::route('GET', 'profile/taylor/1')->uri);
+	}
+
+	/**
+	 * Test that optional wildcards can be routed.
+	 *
+	 * @group laravel
+	 */
+	public function testOptionalWildcardsCanBeRouted()
+	{
+		Route::get('user/(:num?)', function() {});
+		Route::get('profile/(:any)/(:any?)', function() {});
+
+		$this->assertNull(Router::route('GET', 'user/taylor'));
+		$this->assertEquals('user/(:num?)', Router::route('GET', 'user')->uri);
+		$this->assertEquals(array(25), Router::route('GET', 'user/25')->parameters);
+		$this->assertEquals('user/(:num?)', Router::route('GET', 'user/1')->uri);
+
+		$this->assertNull(Router::route('GET', 'profile/taylor/otwell/test'));
+		$this->assertEquals('profile/(:any)/(:any?)', Router::route('GET', 'profile/taylor')->uri);
+		$this->assertEquals('profile/(:any)/(:any?)', Router::route('GET', 'profile/taylor/25')->uri);
+		$this->assertEquals('profile/(:any)/(:any?)', Router::route('GET', 'profile/taylor/otwell')->uri);
+		$this->assertEquals(array('taylor', 'otwell'), Router::route('GET', 'profile/taylor/otwell')->parameters);
+	}
+
+	/**
+	 * Test that basic controller routing is working.
+	 *
+	 * @group laravel
+	 */
+	public function testBasicRouteToControllerIsRouted()
+	{
+		$this->assertEquals('auth@(:1)', Router::route('GET', 'auth')->action['uses']);
+		$this->assertEquals('home@(:1)', Router::route('GET', 'home/index')->action['uses']);
+		$this->assertEquals('home@(:1)', Router::route('GET', 'home/profile')->action['uses']);
+		$this->assertEquals('admin.panel@(:1)', Router::route('GET', 'admin/panel')->action['uses']);
+		$this->assertEquals('admin.panel@(:1)', Router::route('GET', 'admin/panel/show')->action['uses']);
+	}
+
+	/**
+	 * Test basic bundle route resolution.
+	 *
+	 * @group laravel
+	 */
+	public function testRoutesToBundlesCanBeResolved()
+	{
+		$this->assertNull(Router::route('GET', 'dashboard/foo'));
+		$this->assertEquals('dashboard', Router::route('GET', 'dashboard')->uri);
+	}
+
+	/**
+	 * Test bundle controller route resolution.
+	 *
+	 * @group laravel
+	 */
+	public function testBundleControllersCanBeResolved()
+	{
+		$this->assertEquals('dashboard::panel@(:1)', Router::route('GET', 'dashboard/panel')->action['uses']);
+		$this->assertEquals('dashboard::panel@(:1)', Router::route('GET', 'dashboard/panel/show')->action['uses']);
+	}
+
+	/**
+	 * Test foreign characters can be used in routes.
+	 *
+	 * @group laravel
+	 */
+	public function testForeignCharsInRoutes()
+	{
+		Route::get(urlencode('ู…ุฏุฑุณ_ุฑูŠุงุถูŠุงุช').'/(:any)', function() {});
+		Route::get(urlencode('ู…ุฏุฑุณ_ุฑูŠุงุถูŠุงุช'), function() {});
+		Route::get(urlencode('ร‡ล“ลช'), function() {});
+		Route::get(urlencode('็งใฏๆ–™็†ใŒๅคงๅฅฝใ'), function() {});
+
+		$this->assertEquals(array(urlencode('ู…ุฏุฑุณ_ุฑูŠุงุถูŠุงุช')), Router::route('GET', urlencode('ู…ุฏุฑุณ_ุฑูŠุงุถูŠุงุช').'/'.urlencode('ู…ุฏุฑุณ_ุฑูŠุงุถูŠุงุช'))->parameters);
+		$this->assertEquals(urlencode('ู…ุฏุฑุณ_ุฑูŠุงุถูŠุงุช'), Router::route('GET', urlencode('ู…ุฏุฑุณ_ุฑูŠุงุถูŠุงุช'))->uri);
+		$this->assertEquals(urlencode('ร‡ล“ลช'), Router::route('GET', urlencode('ร‡ล“ลช'))->uri);
+		$this->assertEquals(urlencode('็งใฏๆ–™็†ใŒๅคงๅฅฝใ'), Router::route('GET', urlencode('็งใฏๆ–™็†ใŒๅคงๅฅฝใ'))->uri);
+	}
+
+}

+ 443 - 0
laravel/tests/cases/session.test.php

@@ -0,0 +1,443 @@
+<?php
+
+use Laravel\Session;
+use Laravel\Session\Payload;
+
+class DummyPayload {
+
+	public function test() { return 'Foo'; }
+
+}
+
+class SessionTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Setup the testing environment.
+	 */
+	public function setUp()
+	{
+		Config::set('application.key', 'foo');
+		Session::$instance = null;
+	}
+
+	/**
+	 * Tear down the testing environment.
+	 */
+	public function tearDown()
+	{
+		Config::set('application.key', '');
+		Session::$instance = null;
+	}
+
+	/**
+	 * Test the __callStatic method.
+	 *
+	 * @group laravel
+	 */
+	public function testPayloadCanBeCalledStaticly()
+	{
+		Session::$instance = new DummyPayload;
+		$this->assertEquals('Foo', Session::test());
+	}
+
+	/**
+	 * Test the Session::started method.
+	 *
+	 * @group laravel
+	 */
+	public function testStartedMethodIndicatesIfSessionIsStarted()
+	{
+		$this->assertFalse(Session::started());
+		Session::$instance = 'foo';
+		$this->assertTrue(Session::started());
+	}
+
+	/**
+	 * Test the Payload::load method.
+	 *
+	 * @group laravel
+	 */
+	public function testLoadMethodCreatesNewSessionWithNullIDGiven()
+	{
+		$payload = $this->getPayload();
+		$payload->load(null);
+		$this->verifyNewSession($payload);
+	}
+
+	/**
+	 * Test the Payload::load method.
+	 *
+	 * @group laravel
+	 */
+	public function testLoadMethodCreatesNewSessionWhenSessionIsExpired()
+	{
+		$payload = $this->getPayload();
+
+		$session = $this->getSession();
+		$session['last_activity'] = time() - 10000;
+
+		$payload->driver->expects($this->any())
+						->method('load')
+						->will($this->returnValue($session));
+
+		$payload->load('foo');
+
+		$this->verifyNewSession($payload);
+		$this->assertTrue($payload->session['id'] !== $session['id']);
+	}
+
+	/**
+	 * Assert that a session is new.
+	 *
+	 * @param  Payload  $payload
+	 * @return void
+	 */
+	protected function verifyNewSession($payload)
+	{
+		$this->assertFalse($payload->exists);
+		$this->assertTrue(isset($payload->session['id']));
+		$this->assertEquals(array(), $payload->session['data'][':new:']);
+		$this->assertEquals(array(), $payload->session['data'][':old:']);
+		$this->assertTrue(isset($payload->session['data'][Session::csrf_token]));
+	}
+
+	/**
+	 * Test the Payload::load method.
+	 *
+	 * @group laravel
+	 */
+	public function testLoadMethodSetsValidSession()
+	{
+		$payload = $this->getPayload();
+
+		$session = $this->getSession();
+
+		$payload->driver->expects($this->any())
+						->method('load')
+						->will($this->returnValue($session));
+
+		$payload->load('foo');
+
+		$this->assertEquals($session, $payload->session);
+	}
+
+	/**
+	 * Test the Payload::load method.
+	 *
+	 * @group laravel
+	 */
+	public function testLoadMethodSetsCSRFTokenIfDoesntExist()
+	{
+		$payload = $this->getPayload();
+
+		$session = $this->getSession();
+
+		unset($session['data']['csrf_token']);
+
+		$payload->driver->expects($this->any())
+						->method('load')
+						->will($this->returnValue($session));
+
+		$payload->load('foo');
+
+		$this->assertEquals('foo', $payload->session['id']);
+		$this->assertTrue(isset($payload->session['data']['csrf_token']));
+	}
+
+	/**
+	 * Test the various data retrieval methods.
+	 *
+	 * @group laravel
+	 */
+	public function testSessionDataCanBeRetrievedProperly()
+	{
+		$payload = $this->getPayload();
+
+		$payload->session = $this->getSession();
+
+		$this->assertTrue($payload->has('name'));
+		$this->assertEquals('Taylor', $payload->get('name'));
+		$this->assertFalse($payload->has('foo'));
+		$this->assertEquals('Default', $payload->get('foo', 'Default'));
+		$this->assertTrue($payload->has('votes'));
+		$this->assertEquals(10, $payload->get('votes'));
+		$this->assertTrue($payload->has('state'));
+		$this->assertEquals('AR', $payload->get('state'));
+	}
+
+	/**
+	 * Test the various data manipulation methods.
+	 *
+	 * @group laravel
+	 */
+	public function testDataCanBeSetProperly()
+	{
+		$payload = $this->getPayload();
+
+		$payload->session = $this->getSession();
+
+		// Test the "put" and "flash" methods.
+		$payload->put('name', 'Weldon');
+		$this->assertEquals('Weldon', $payload->session['data']['name']);
+		$payload->flash('language', 'php');
+		$this->assertEquals('php', $payload->session['data'][':new:']['language']);
+
+		// Test the "reflash" method.
+		$payload->session['data'][':new:'] = array('name' => 'Taylor');
+		$payload->session['data'][':old:'] = array('age' => 25);
+		$payload->reflash();
+		$this->assertEquals(array('name' => 'Taylor', 'age' => 25), $payload->session['data'][':new:']);
+
+		// Test the "keep" method.
+		$payload->session['data'][':new:'] = array();
+		$payload->keep(array('age'));
+		$this->assertEquals(25, $payload->session['data'][':new:']['age']);
+	}
+
+	/**
+	 * Test the Payload::forget method.
+	 *
+	 * @group laravel
+	 */
+	public function testSessionDataCanBeForgotten()
+	{
+		$payload = $this->getPayload();
+
+		$payload->session = $this->getSession();
+
+		$this->assertTrue(isset($payload->session['data']['name']));
+		$payload->forget('name');
+		$this->assertFalse(isset($payload->session['data']['name']));
+	}
+
+	/**
+	 * Test the Payload::flush method.
+	 *
+	 * @group laravel
+	 */
+	public function testFlushMaintainsTokenButDeletesEverythingElse()
+	{
+		$payload = $this->getPayload();
+
+		$payload->session = $this->getSession();
+
+		$this->assertTrue(isset($payload->session['data']['name']));
+		$payload->flush();
+		$this->assertFalse(isset($payload->session['data']['name']));
+		$this->assertEquals('bar', $payload->session['data']['csrf_token']);
+		$this->assertEquals(array(), $payload->session['data'][':new:']);
+		$this->assertEquals(array(), $payload->session['data'][':old:']);
+	}
+
+	/**
+	 * Test the Payload::regenerate method.
+	 *
+	 * @group laravel
+	 */
+	public function testRegenerateMethodSetsNewIDAndTurnsOffExistenceIndicator()
+	{
+		$payload = $this->getPayload();
+
+		$payload->sesion = $this->getSession();
+		$payload->exists = true;
+		$payload->regenerate();
+
+		$this->assertFalse($payload->exists);
+		$this->assertTrue(strlen($payload->session['id']) == 40);
+	}
+
+	/**
+	 * Test the Payload::token method.
+	 *
+	 * @group laravel
+	 */
+	public function testTokenMethodReturnsCSRFToken()
+	{
+		$payload = $this->getPayload();
+		$payload->session = $this->getSession();
+
+		$this->assertEquals('bar', $payload->token());
+	}
+
+	/**
+	 * Test the Payload::save method.
+	 *
+	 * @group laravel
+	 */
+	public function testSaveMethodCorrectlyCallsDriver()
+	{
+		$payload = $this->getPayload();
+		$session = $this->getSession();
+		$payload->session = $session;
+		$payload->exists = true;
+		$config = Laravel\Config::get('session');
+
+		$expect = $session;
+		$expect['data'][':old:'] = $session['data'][':new:'];
+		$expect['data'][':new:'] = array();
+
+		$payload->driver->expects($this->once())
+						->method('save')
+						->with($this->equalTo($expect), $this->equalTo($config), $this->equalTo(true));
+
+		$payload->save();
+
+		$this->assertEquals($session['data'][':new:'], $payload->session['data'][':old:']);
+	}
+
+	/**
+	 * Test the Payload::save method.
+	 *
+	 * @group laravel
+	 */
+	public function testSaveMethodSweepsIfSweeperAndOddsHitWithTimeGreaterThanThreshold()
+	{
+		Config::set('session.sweepage', array(100, 100));
+
+		$payload = $this->getPayload();
+		$payload->driver = $this->getMock('Laravel\\Session\\Drivers\\File', array('save', 'sweep'), array(null));
+		$payload->session = $this->getSession();
+
+		$expiration = time() - (Config::get('session.lifetime') * 60);
+
+		// Here we set the time to the expected expiration minus 5 seconds, just to
+		// allow plenty of room for PHP execution. In the next test, we'll do the
+		// same thing except add 5 seconds to check that the time is between a
+		// given window.
+		$payload->driver->expects($this->once())
+						->method('sweep')
+						->with($this->greaterThan($expiration - 5));
+
+		$payload->save();
+
+		Config::set('session.sweepage', array(2, 100));
+	}
+
+	/**
+	 * Test the Payload::save method.
+	 *
+	 * @group laravel
+	 */
+	public function testSaveMethodSweepsIfSweeperAndOddsHitWithTimeLessThanThreshold()
+	{
+		Config::set('session.sweepage', array(100, 100));
+
+		$payload = $this->getPayload();
+		$payload->driver = $this->getMock('Laravel\\Session\\Drivers\\File', array('save', 'sweep'), array(null));
+		$payload->session = $this->getSession();
+
+		$expiration = time() - (Config::get('session.lifetime') * 60);
+
+		$payload->driver->expects($this->once())
+						->method('sweep')
+						->with($this->lessThan($expiration + 5));
+
+		$payload->save();
+
+		Config::set('session.sweepage', array(2, 100));
+	}
+
+	/**
+	 * Test that the session sweeper is never called if not a sweeper.
+	 *
+	 * @group laravel
+	 */
+	public function testSweeperShouldntBeCalledIfDriverIsntSweeper()
+	{
+		Config::set('session.sweepage', array(100, 100));
+
+		$payload = $this->getPayload();
+		$payload->driver = $this->getMock('Laravel\\Session\\Drivers\\APC', array('save', 'sweep'), array(), '', false);
+		$payload->session = $this->getSession();
+
+		$payload->driver->expects($this->never())->method('sweep');
+
+		$payload->save();
+
+		Config::set('session.sweepage', array(2, 100));
+	}
+
+	/**
+	 * Test the Payload::save method.
+	 *
+	 * @group laravel
+	 */
+	public function testSaveMethodSetsCookieWithCorrectValues()
+	{
+		$payload = $this->getPayload();
+		$payload->session = $this->getSession();
+		$payload->save();
+
+		$this->assertTrue(isset(Cookie::$jar[Config::get('session.cookie')]));
+
+		$cookie = Cookie::$jar[Config::get('session.cookie')];
+
+		$this->assertEquals('foo', $cookie['value']);
+		// Shouldn't be able to test this cause session.lifetime store number of minutes 
+		// while cookie expiration store timestamp when it going to expired.
+		// $this->assertEquals(Config::get('session.lifetime'), $cookie['expiration']);
+		$this->assertEquals(Config::get('session.domain'), $cookie['domain']);
+		$this->assertEquals(Config::get('session.path'), $cookie['path']);
+		$this->assertEquals(Config::get('session.secure'), $cookie['secure']);
+	}
+
+	/**
+	 * Test the Session::activity method.
+	 *
+	 * @group laravel
+	 */
+	public function testActivityMethodReturnsLastActivity()
+	{
+		$payload = $this->getPayload();
+		$payload->session['last_activity'] = 10;
+		$this->assertEquals(10, $payload->activity());
+	}
+
+	/**
+	 * Get a session payload instance.
+	 *
+	 * @return Payload
+	 */
+	protected function getPayload()
+	{
+		return new Payload($this->getMockDriver());
+	}
+
+	/**
+	 * Get a mock driver instance.
+	 *
+	 * @return Driver
+	 */
+	protected function getMockDriver()
+	{
+		$mock = $this->getMock('Laravel\\Session\\Drivers\\Driver', array('id', 'load', 'save', 'delete'));
+
+		$mock->expects($this->any())->method('id')->will($this->returnValue(Str::random(40)));
+
+		return $mock;
+	}
+
+	/**
+	 * Get a dummy session.
+	 *
+	 * @return array
+	 */
+	protected function getSession()
+	{
+		return array(
+			'id'            => 'foo',
+			'last_activity' => time(),
+			'data'          => array(
+				'name'       => 'Taylor',
+				'age'        => 25,
+				'csrf_token' => 'bar',
+				':new:'      => array(
+						'votes' => 10,
+				),
+				':old:'      => array(
+						'state' => 'AR',
+				),
+		));
+	}
+
+}

+ 133 - 0
laravel/tests/cases/str.test.php

@@ -0,0 +1,133 @@
+<?php
+
+class StrTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Test the Str::encoding method.
+	 *
+	 * @group laravel
+	 */
+	public function testEncodingShouldReturnApplicationEncoding()
+	{
+		$this->assertEquals('UTF-8', Config::get('application.encoding'));
+		Config::set('application.encoding', 'foo');
+		$this->assertEquals('foo', Config::get('application.encoding'));
+		Config::set('application.encoding', 'UTF-8');
+	}
+
+	/**
+	 * Test the Str::length method.
+	 *
+	 * @group laravel
+	 */
+	public function testStringLengthIsCorrect()
+	{
+		$this->assertEquals(6, Str::length('Taylor'));
+		$this->assertEquals(5, Str::length('ใƒฉใƒ‰ใ‚ฏใƒชใƒ•'));
+	}
+
+	/**
+	 * Test the Str::lower method.
+	 *
+	 * @group laravel
+	 */
+	public function testStringCanBeConvertedToLowercase()
+	{
+		$this->assertEquals('taylor', Str::lower('TAYLOR'));
+		$this->assertEquals('ฮฌฯ‡ฮนฯƒฯ„ฮท', Str::lower('ฮ†ฮงฮ™ฮฃฮคฮ—'));
+	}
+
+	/**
+	 * Test the Str::upper method.
+	 *
+	 * @group laravel
+	 */
+	public function testStringCanBeConvertedToUppercase()
+	{
+		$this->assertEquals('TAYLOR', Str::upper('taylor'));
+		$this->assertEquals('ฮ†ฮงฮ™ฮฃฮคฮ—', Str::upper('ฮฌฯ‡ฮนฯƒฯ„ฮท'));
+	}
+
+	/**
+	 * Test the Str::title method.
+	 *
+	 * @group laravel
+	 */
+	public function testStringCanBeConvertedToTitleCase()
+	{
+		$this->assertEquals('Taylor', Str::title('taylor'));
+		$this->assertEquals('ฮ†ฯ‡ฮนฯƒฯ„ฮท', Str::title('ฮฌฯ‡ฮนฯƒฯ„ฮท'));
+	}
+
+	/**
+	 * Test the Str::limit method.
+	 *
+	 * @group laravel
+	 */
+	public function testStringCanBeLimitedByCharacters()
+	{
+		$this->assertEquals('Tay...', Str::limit('Taylor', 3));
+		$this->assertEquals('Taylor', Str::limit('Taylor', 6));
+		$this->assertEquals('Tay___', Str::limit('Taylor', 3, '___'));
+	}
+
+	/**
+	 * Test the Str::words method.
+	 *
+	 * @group laravel
+	 */
+	public function testStringCanBeLimitedByWords()
+	{
+		$this->assertEquals('Taylor...', Str::words('Taylor Otwell', 1));
+		$this->assertEquals('Taylor___', Str::words('Taylor Otwell', 1, '___'));
+		$this->assertEquals('Taylor Otwell', Str::words('Taylor Otwell', 3));
+	}
+
+	/**
+	 * Test the Str::plural and Str::singular methods.
+	 *
+	 * @group laravel
+	 */
+	public function testStringsCanBeSingularOrPlural()
+	{
+		$this->assertEquals('user', Str::singular('users'));
+		$this->assertEquals('users', Str::plural('user'));
+		$this->assertEquals('User', Str::singular('Users'));
+		$this->assertEquals('Users', Str::plural('User'));
+		$this->assertEquals('user', Str::plural('user', 1));
+		$this->assertEquals('users', Str::plural('user', 2));
+	}
+
+	/**
+	 * Test the Str::slug method.
+	 *
+	 * @group laravel
+	 */
+	public function testStringsCanBeSlugged()
+	{
+		$this->assertEquals('my-new-post', Str::slug('My nEw post!!!'));
+		$this->assertEquals('my_new_post', Str::slug('My nEw post!!!', '_'));
+	}
+
+	/**
+	 * Test the Str::classify method.
+	 *
+	 * @group laravel
+	 */
+	public function testStringsCanBeClassified()
+	{
+		$this->assertEquals('Something_Else', Str::classify('something.else'));
+		$this->assertEquals('Something_Else', Str::classify('something_else'));
+	}
+
+	/**
+	 * Test the Str::random method.
+	 *
+	 * @group laravel
+	 */
+	public function testRandomStringsCanBeGenerated()
+	{
+		$this->assertEquals(40, strlen(Str::random(40)));
+	}
+
+}

+ 75 - 0
laravel/tests/cases/uri.test.php

@@ -0,0 +1,75 @@
+<?php
+
+use Symfony\Component\HttpFoundation\LaravelRequest as RequestFoundation;
+
+class URITest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Destroy the test environment.
+	 */
+	public function tearDown()
+	{
+		$_SERVER = array();
+		URI::$uri = null;
+		URI::$segments = array();
+	}
+
+	/**
+	 * Set this request's URI to the given string
+	 * 
+	 * @param string  $uri
+	 */
+	protected function setRequestUri($uri)
+	{
+		// FIXME: Ugly hack, but old contents from previous requests seem to
+		// trip up the Foundation class.
+		$_FILES = array();
+		
+		$_SERVER['REQUEST_URI'] = $uri;
+		Request::$foundation = RequestFoundation::createFromGlobals();
+	}
+
+	/**
+	 * Test the URI::current method.
+	 *
+	 * @group laravel
+	 * @dataProvider requestUriProvider
+	 */
+	public function testCorrectURIIsReturnedByCurrentMethod($uri, $expectation)
+	{
+		$this->setRequestUri($uri);
+
+		$this->assertEquals($expectation, URI::current());
+	}
+
+	/**
+	 * Test the URI::segment method.
+	 *
+	 * @group laravel
+	 */
+	public function testSegmentMethodReturnsAURISegment()
+	{
+		$this->setRequestUri('/user/profile');
+
+		$this->assertEquals('user', URI::segment(1));
+		$this->assertEquals('profile', URI::segment(2));
+	}
+
+	/**
+	 * Data provider for the URI::current test.
+	 */
+	public function requestUriProvider()
+	{
+		return array(
+			array('/user', 'user'),
+			array('/user/', 'user'),
+			array('', '/'),
+			array('/', '/'),
+			array('//', '/'),
+			array('/user', 'user'),
+			array('/user/', 'user'),
+			array('/user/profile', 'user/profile'),
+		);
+	}
+
+}

+ 106 - 0
laravel/tests/cases/url.test.php

@@ -0,0 +1,106 @@
+<?php
+
+use Laravel\Routing\Router;
+
+class URLTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Setup the test enviornment.
+	 */
+	public function setUp()
+	{
+		URL::$base = null;
+		Router::$routes = array();
+		Router::$names = array();
+		Router::$uses = array();
+		Router::$fallback = array();
+		Config::set('application.url', 'http://localhost');
+	}
+
+	/**
+	 * Destroy the test enviornment.
+	 */
+	public function tearDown()
+	{
+		$_SERVER = array();
+		Router::$routes = array();
+		Router::$names = array();
+		Router::$uses = array();
+		Router::$fallback = array();
+		Config::set('application.ssl', true);
+		Config::set('application.url', '');
+		Config::set('application.index', 'index.php');
+	}
+
+	/**
+	 * Test the URL::to method.
+	 *
+	 * @group laravel
+	 */
+	public function testToMethodGeneratesURL()
+	{
+		$this->assertEquals('http://localhost/index.php/user/profile', URL::to('user/profile'));
+		$this->assertEquals('https://localhost/index.php/user/profile', URL::to('user/profile', true));
+
+		Config::set('application.index', '');
+
+		$this->assertEquals('http://localhost/user/profile', URL::to('user/profile'));
+		$this->assertEquals('https://localhost/user/profile', URL::to('user/profile', true));
+
+		Config::set('application.ssl', false);
+
+		$this->assertEquals('http://localhost/user/profile', URL::to('user/profile', true));
+	}
+
+	/**
+	 * Test the URL::to_action method.
+	 *
+	 * @group laravel
+	 */
+	public function testToActionMethodGeneratesURLToControllerAction()
+	{
+		Route::get('foo/bar/(:any?)', 'foo@baz');
+		$this->assertEquals('http://localhost/index.php/x/y', URL::to_action('x@y'));
+		$this->assertEquals('http://localhost/index.php/x/y/Taylor', URL::to_action('x@y', array('Taylor')));
+		$this->assertEquals('http://localhost/index.php/foo/bar', URL::to_action('foo@baz'));
+		$this->assertEquals('http://localhost/index.php/foo/bar/Taylor', URL::to_action('foo@baz', array('Taylor')));
+	}
+
+	/**
+	 * Test the URL::to_asset method.
+	 *
+	 * @group laravel
+	 */
+	public function testToAssetGeneratesURLWithoutFrontControllerInURL()
+	{
+		$this->assertEquals('http://localhost/image.jpg', URL::to_asset('image.jpg'));
+		$this->assertEquals('https://localhost/image.jpg', URL::to_asset('image.jpg', true));
+
+		Config::set('application.index', '');
+
+		$this->assertEquals('http://localhost/image.jpg', URL::to_asset('image.jpg'));
+		$this->assertEquals('https://localhost/image.jpg', URL::to_asset('image.jpg', true));
+
+		Request::foundation()->server->add(array('HTTPS' => 'on'));
+
+		$this->assertEquals('https://localhost/image.jpg', URL::to_asset('image.jpg'));
+	}
+
+	/**
+	 * Test the URL::to_route method.
+	 *
+	 * @group laravel
+	 */
+	public function testToRouteMethodGeneratesURLsToRoutes()
+	{
+		Route::get('url/test', array('as' => 'url-test'));
+		Route::get('url/test/(:any)/(:any?)', array('as' => 'url-test-2'));
+		Route::get('url/secure/(:any)/(:any?)', array('as' => 'url-test-3', 'https' => true));
+
+		$this->assertEquals('http://localhost/index.php/url/test', URL::to_route('url-test'));
+		$this->assertEquals('http://localhost/index.php/url/test/taylor', URL::to_route('url-test-2', array('taylor')));
+		$this->assertEquals('https://localhost/index.php/url/secure/taylor', URL::to_route('url-test-3', array('taylor')));
+		$this->assertEquals('http://localhost/index.php/url/test/taylor/otwell', URL::to_route('url-test-2', array('taylor', 'otwell')));
+	}
+
+}

+ 669 - 0
laravel/tests/cases/validator.test.php

@@ -0,0 +1,669 @@
+<?php
+
+class ValidatorTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Setup the test environment.
+	 */
+	public function setUp()
+	{
+		Config::set('database.default', 'sqlite');
+	}
+
+	/**
+	 * Tear down the test environment.
+	 */
+	public function tearDown()
+	{
+		Config::set('database.default', 'mysql');
+		$_FILES = array();
+	}
+
+	/**
+	 * Test the required validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testRequiredRule()
+	{
+		$input = array('name' => 'Taylor Otwell');
+		$rules = array('name' => 'required');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['name'] = '';
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+
+		unset($input['name']);
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+
+		$_FILES['name']['tmp_name'] = 'foo';
+		$this->assertTrue(Validator::make($_FILES, $rules)->valid());
+
+		$_FILES['name']['tmp_name'] = '';
+		$this->assertFalse(Validator::make($_FILES, $rules)->valid());
+	}
+
+	/**
+	 * Test the confirmed validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheConfirmedRule()
+	{
+		$input = array('password' => 'foo', 'password_confirmation' => 'foo');
+		$rules = array('password' => 'confirmed');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['password_confirmation'] = 'foo_bar';
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+
+		unset($input['password_confirmation']);
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+	}
+
+	/**
+	 * Test the different validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheDifferentRule()
+	{
+		$input = array('password' => 'foo', 'password_confirmation' => 'bar');
+		$rules = array('password' => 'different:password_confirmation');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['password_confirmation'] = 'foo';
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+
+		unset($input['password_confirmation']);
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+	}
+
+	/**
+	 * Test the accepted validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheAcceptedRule()
+	{
+		$input = array('terms' => '1');
+		$rules = array('terms' => 'accepted');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['terms'] = 'yes';
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['terms'] = '2';
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+
+		// The accepted rule implies required, so should fail if field not present.
+		unset($input['terms']);
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+	}
+
+	/**
+	 * Test the numeric validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheNumericRule()
+	{
+		$input = array('amount' => '1.21');
+		$rules = array('amount' => 'numeric');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['amount'] = '1';
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['amount'] = 1.2;
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['amount'] = '1.2a';
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+	}
+
+	/**
+	 * Test the integer validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheIntegerRule()
+	{
+		$input = array('amount' => '1');
+		$rules = array('amount' => 'integer');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['amount'] = '0';
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['amount'] = 1.2;
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+
+		$input['amount'] = '1.2a';
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+	}
+
+	/**
+	 * Test the size validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheSizeRule()
+	{
+		$input = array('amount' => '1.21');
+		$rules = array('amount' => 'numeric|size:1.21');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$rules = array('amount' => 'numeric|size:1');
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+
+		// If no numeric rule is on the field, it is treated as a string
+		$input = array('amount' => '111');
+		$rules = array('amount' => 'size:3');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$rules = array('amount' => 'size:4');
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+
+		// The size rules checks kilobytes on files
+		$_FILES['photo']['tmp_name'] = 'foo';
+		$_FILES['photo']['size'] = 10240;
+		$rules = array('photo' => 'size:10');
+		$this->assertTrue(Validator::make($_FILES, $rules)->valid());
+
+		$_FILES['photo']['size'] = 14000;
+		$this->assertFalse(Validator::make($_FILES, $rules)->valid());
+	}
+
+	/**
+	 * Test the between validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheBetweenRule()
+	{
+		$input = array('amount' => '1.21');
+		$rules = array('amount' => 'numeric|between:1,2');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$rules = array('amount' => 'numeric|between:2,3');
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+
+		// If no numeric rule is on the field, it is treated as a string
+		$input = array('amount' => '111');
+		$rules = array('amount' => 'between:1,3');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$rules = array('amount' => 'between:100,111');
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+
+		// The size rules checks kilobytes on files
+		$_FILES['photo']['tmp_name'] = 'foo';
+		$_FILES['photo']['size'] = 10240;
+		$rules = array('photo' => 'between:9,11');
+		$this->assertTrue(Validator::make($_FILES, $rules)->valid());
+
+		$_FILES['photo']['size'] = 14000;
+		$this->assertFalse(Validator::make($_FILES, $rules)->valid());
+	}
+
+	/**
+	 * Test the between validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheMinRule()
+	{
+		$input = array('amount' => '1.21');
+		$rules = array('amount' => 'numeric|min:1');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$rules = array('amount' => 'numeric|min:2');
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+
+		// If no numeric rule is on the field, it is treated as a string
+		$input = array('amount' => '01');
+		$rules = array('amount' => 'min:2');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$rules = array('amount' => 'min:3');
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+
+		// The size rules checks kilobytes on files
+		$_FILES['photo']['tmp_name'] = 'foo';
+		$_FILES['photo']['size'] = 10240;
+		$rules = array('photo' => 'min:9');
+		$this->assertTrue(Validator::make($_FILES, $rules)->valid());
+
+		$_FILES['photo']['size'] = 8000;
+		$this->assertFalse(Validator::make($_FILES, $rules)->valid());
+	}
+
+	/**
+	 * Test the between validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheMaxRule()
+	{
+		$input = array('amount' => '1.21');
+		$rules = array('amount' => 'numeric|max:2');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$rules = array('amount' => 'numeric|max:1');
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+
+		// If no numeric rule is on the field, it is treated as a string
+		$input = array('amount' => '01');
+		$rules = array('amount' => 'max:3');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$rules = array('amount' => 'max:1');
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+
+		// The size rules checks kilobytes on files
+		$_FILES['photo']['tmp_name'] = 'foo';
+		$_FILES['photo']['size'] = 10240;
+		$rules = array('photo' => 'max:11');
+		$this->assertTrue(Validator::make($_FILES, $rules)->valid());
+
+		$_FILES['photo']['size'] = 140000;
+		$this->assertFalse(Validator::make($_FILES, $rules)->valid());
+	}
+
+	/**
+	 * Test the in validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheInRule()
+	{
+		$input = array('size' => 'L');
+		$rules = array('size' => 'in:S,M,L');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['size'] = 'XL';
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+	}
+
+	/**
+	 * Test the not-in validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheNotInRule()
+	{
+		$input = array('size' => 'L');
+		$rules = array('size' => 'not_in:S,M,L');
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+
+		$input['size'] = 'XL';
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+	}
+
+	/**
+	 * Test the IP validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheIPRule()
+	{
+		$input = array('ip' => '192.168.1.1');
+		$rules = array('ip' => 'ip');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['ip'] = '192.111';
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+	}
+
+	/**
+	 * Test the e-mail validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheEmailRule()
+	{
+		$input = array('email' => 'example@gmail.com');
+		$rules = array('email' => 'email');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['email'] = 'blas-asok';
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+	}
+
+	/**
+	 * Test the URL validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheUrlRule()
+	{
+		$input = array('url' => 'http://www.google.com');
+		$rules = array('url' => 'url');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['url'] = 'blas-asok';
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+	}
+
+	/**
+	 * Test the active URL validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheActiveUrlRule()
+	{
+		$input = array('url' => 'http://google.com');
+		$rules = array('url' => 'active_url');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['url'] = 'http://asdlk-aselkaiwels.com';
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+	}
+
+	/**
+	 * Test the image validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheImageRule()
+	{
+		$_FILES['photo']['tmp_name'] = path('storage').'files/desert.jpg';
+		$rules = array('photo' => 'image');
+		$this->assertTrue(Validator::make($_FILES, $rules)->valid());
+
+		$_FILES['photo']['tmp_name'] = path('app').'routes.php';
+		$this->assertFalse(Validator::make($_FILES, $rules)->valid());
+	}
+
+	/**
+	 * Test the alpha validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheAlphaRule()
+	{
+		$input = array('name' => 'TaylorOtwell');
+		$rules = array('name' => 'alpha');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['name'] = 'Taylor Otwell';
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+	}
+
+	/**
+	 * Test the alpha_num validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheAlphaNumRule()
+	{
+		$input = array('name' => 'TaylorOtwell1');
+		$rules = array('name' => 'alpha_num');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['name'] = 'Taylor Otwell';
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+	}
+
+	/**
+	 * Test the alpha_num validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheAlphaDashRule()
+	{
+		$input = array('name' => 'Taylor-Otwell_1');
+		$rules = array('name' => 'alpha_dash');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['name'] = 'Taylor Otwell';
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+	}
+
+	/**
+	 * Test the mimes validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testTheMimesRule()
+	{
+		$_FILES['file']['tmp_name'] = path('app').'routes.php';
+		$rules = array('file' => 'mimes:php,txt');
+		$this->assertTrue(Validator::make($_FILES, $rules)->valid());
+
+		$rules = array('file' => 'mimes:jpg,bmp');
+		$this->assertFalse(Validator::make($_FILES, $rules)->valid());
+
+		$_FILES['file']['tmp_name'] = path('storage').'files/desert.jpg';
+		$rules['file'] = 'mimes:jpg,bmp';
+		$this->assertTrue(Validator::make($_FILES, $rules)->valid());
+
+		$rules['file'] = 'mimes:txt,bmp';
+		$this->assertFalse(Validator::make($_FILES, $rules)->valid());
+	}
+
+	/**
+	 * Test the unique validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testUniqueRule()
+	{
+		$input = array('code' => 'ZZ');
+		$rules = array('code' => 'unique:validation_unique');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input = array('code' => 'AR');
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+
+		$rules = array('code' => 'unique:validation_unique,code,AR,code');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+	}
+
+	/**
+	 * Tests the exists validation rule.
+	 *
+	 * @group laravel
+	 */
+	public function testExistsRule()
+	{
+		$input = array('code' => 'TX');
+		$rules = array('code' => 'exists:validation_unique');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['code'] = array('TX', 'NY');
+		$rules = array('code' => 'exists:validation_unique,code');
+		$this->assertTrue(Validator::make($input, $rules)->valid());
+
+		$input['code'] = array('TX', 'XX');
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+
+		$input['code'] = 'XX';
+		$this->assertFalse(Validator::make($input, $rules)->valid());
+	}
+
+	/**
+	 * Test that the validator sets the correct messages.
+	 *
+	 * @group laravel
+	 */
+	public function testCorrectMessagesAreSet()
+	{
+		$lang = require path('app').'language/en/validation.php';
+	
+		$input = array('email' => 'example-foo');
+		$rules = array('name' => 'required', 'email' => 'required|email');
+		$v = Validator::make($input, $rules);
+		$v->valid();
+		$messages = $v->errors;
+		$this->assertInstanceOf('Laravel\\Messages', $messages);
+		$this->assertEquals(str_replace(':attribute', 'name', $lang['required']), $messages->first('name'));
+		$this->assertEquals(str_replace(':attribute', 'email', $lang['email']), $messages->first('email'));
+	}
+
+	/**
+	 * Test that custom messages are recognized.
+	 *
+	 * @group laravel
+	 */
+	public function testCustomMessagesAreRecognize()
+	{
+		$messages = array('required' => 'Required!');
+		$rules = array('name' => 'required');
+		$v = Validator::make(array(), $rules, $messages);
+		$v->valid();
+		$this->assertEquals('Required!', $v->errors->first('name'));
+
+		$messages['email_required'] = 'Email Required!';
+		$rules = array('name' => 'required', 'email' => 'required');
+		$v = Validator::make(array(), $rules, $messages);
+		$v->valid();
+		$this->assertEquals('Required!', $v->errors->first('name'));
+		$this->assertEquals('Email Required!', $v->errors->first('email'));
+
+		$rules = array('custom' => 'required');
+		$v = Validator::make(array(), $rules);
+		$v->valid();
+		$this->assertEquals('This field is required!', $v->errors->first('custom'));
+	}
+
+	/**
+	 * Test that size replacements are made on messages.
+	 *
+	 * @group laravel
+	 */
+	public function testNumericSizeReplacementsAreMade()
+	{
+		$lang = require path('app').'language/en/validation.php';
+		
+		$input = array('amount' => 100);
+		$rules = array('amount' => 'numeric|size:80');
+		$v = Validator::make($input, $rules);
+		$v->valid();
+		$this->assertEquals(str_replace(array(':attribute', ':size'), array('amount', '80'), $lang['size']['numeric']), $v->errors->first('amount'));
+
+		$rules = array('amount' => 'numeric|between:70,80');
+		$v = Validator::make($input, $rules);
+		$v->valid();
+		$expect = str_replace(array(':attribute', ':min', ':max'), array('amount', '70', '80'), $lang['between']['numeric']);
+		$this->assertEquals($expect, $v->errors->first('amount'));
+
+		$rules = array('amount' => 'numeric|min:120');
+		$v = Validator::make($input, $rules);
+		$v->valid();
+		$expect = str_replace(array(':attribute', ':min'), array('amount', '120'), $lang['min']['numeric']);
+		$this->assertEquals($expect, $v->errors->first('amount'));
+
+		$rules = array('amount' => 'numeric|max:20');
+		$v = Validator::make($input, $rules);
+		$v->valid();
+		$expect = str_replace(array(':attribute', ':max'), array('amount', '20'), $lang['max']['numeric']);
+		$this->assertEquals($expect, $v->errors->first('amount'));
+	}
+
+	/**
+	 * Test that string size replacements are made on messages.
+	 *
+	 * @group laravel
+	 */
+	public function testStringSizeReplacementsAreMade()
+	{
+		$lang = require path('app').'language/en/validation.php';
+		
+		$input = array('amount' => '100');
+		$rules = array('amount' => 'size:80');
+		$v = Validator::make($input, $rules);
+		$v->valid();
+		$this->assertEquals(str_replace(array(':attribute', ':size'), array('amount', '80'), $lang['size']['string']), $v->errors->first('amount'));
+
+		$rules = array('amount' => 'between:70,80');
+		$v = Validator::make($input, $rules);
+		$v->valid();
+		$expect = str_replace(array(':attribute', ':min', ':max'), array('amount', '70', '80'), $lang['between']['string']);
+		$this->assertEquals($expect, $v->errors->first('amount'));
+
+		$rules = array('amount' => 'min:120');
+		$v = Validator::make($input, $rules);
+		$v->valid();
+		$expect = str_replace(array(':attribute', ':min'), array('amount', '120'), $lang['min']['string']);
+		$this->assertEquals($expect, $v->errors->first('amount'));
+
+		$rules = array('amount' => 'max:2');
+		$v = Validator::make($input, $rules);
+		$v->valid();
+		$expect = str_replace(array(':attribute', ':max'), array('amount', '2'), $lang['max']['string']);
+		$this->assertEquals($expect, $v->errors->first('amount'));
+	}
+
+	/**
+	 * Test that string size replacements are made on messages.
+	 *
+	 * @group laravel
+	 */
+	public function testFileSizeReplacementsAreMade()
+	{
+		$lang = require path('app').'language/en/validation.php';
+		
+		$_FILES['amount']['tmp_name'] = 'foo';
+		$_FILES['amount']['size'] = 10000;
+		$rules = array('amount' => 'size:80');
+		$v = Validator::make($_FILES, $rules);
+		$v->valid();
+		$this->assertEquals(str_replace(array(':attribute', ':size'), array('amount', '80'), $lang['size']['file']), $v->errors->first('amount'));
+
+		$rules = array('amount' => 'between:70,80');
+		$v = Validator::make($_FILES, $rules);
+		$v->valid();
+		$expect = str_replace(array(':attribute', ':min', ':max'), array('amount', '70', '80'), $lang['between']['file']);
+		$this->assertEquals($expect, $v->errors->first('amount'));
+
+		$rules = array('amount' => 'min:120');
+		$v = Validator::make($_FILES, $rules);
+		$v->valid();
+		$expect = str_replace(array(':attribute', ':min'), array('amount', '120'), $lang['min']['file']);
+		$this->assertEquals($expect, $v->errors->first('amount'));
+
+		$rules = array('amount' => 'max:2');
+		$v = Validator::make($_FILES, $rules);
+		$v->valid();
+		$expect = str_replace(array(':attribute', ':max'), array('amount', '2'), $lang['max']['file']);
+		$this->assertEquals($expect, $v->errors->first('amount'));
+	}
+
+	/**
+	 * Test that values get replaced in messages.
+	 *
+	 * @group laravel
+	 */
+	public function testValuesGetReplaced()
+	{
+		$lang = require path('app').'language/en/validation.php';
+
+		$_FILES['file']['tmp_name'] = path('storage').'files/desert.jpg';
+		$rules = array('file' => 'mimes:php,txt');
+		$v = Validator::make($_FILES, $rules);
+		$v->valid();
+
+		$expect = str_replace(array(':attribute', ':values'), array('file', 'php, txt'), $lang['mimes']);
+		$this->assertEquals($expect, $v->errors->first('file'));
+	}
+
+	/**
+	 * Test custom attribute names are replaced.
+	 *
+	 * @group laravel
+	 */
+	public function testCustomAttributesAreReplaced()
+	{
+		$lang = require path('app').'language/en/validation.php';
+
+		$rules = array('test_attribute' => 'required');
+		$v = Validator::make(array(), $rules);
+		$v->valid();
+
+		$expect = str_replace(':attribute', 'attribute', $lang['required']);
+		$this->assertEquals($expect, $v->errors->first('test_attribute'));
+	}
+
+}

+ 255 - 0
laravel/tests/cases/view.test.php

@@ -0,0 +1,255 @@
+<?php
+
+class ViewTest extends PHPUnit_Framework_TestCase {
+
+	/**
+	 * Tear down the testing environment.
+	 */
+	public function tearDown()
+	{
+		View::$shared = array();
+		unset(Event::$events['composing: test.basic']);
+	}
+
+	/**
+	 * Test the View::make method.
+	 *
+	 * @group laravel
+	 */
+	public function testMakeMethodReturnsAViewInstance()
+	{
+		$this->assertInstanceOf('Laravel\\View', View::make('home.index'));
+	}
+
+	/**
+	 * Test the View class constructor.
+	 *
+	 * @group laravel
+	 */
+	public function testViewNameIsSetByConstrutor()
+	{
+		$view = new View('home.index');
+
+		$this->assertEquals('home.index', $view->view);
+	}
+
+	/**
+	 * Test the View class constructor.
+	 *
+	 * @group laravel
+	 */
+	public function testViewIsCreatedWithCorrectPath()
+	{
+		$view = new View('home.index');
+		
+		$this->assertEquals(
+			str_replace(DS, '/', path('app')).'views/home/index.php',
+			str_replace(DS, '/', $view->path)
+		);
+	}
+
+	/**
+	 * Test the View class constructor for bundles.
+	 *
+	 * @group laravel
+	 */
+	public function testBundleViewIsCreatedWithCorrectPath()
+	{
+		$view = new View('home.index');
+
+		$this->assertEquals(
+			str_replace(DS, '/', Bundle::path(DEFAULT_BUNDLE)).'views/home/index.php',
+			str_replace(DS, '/', $view->path)
+		);
+	}
+
+	/**
+	 * Test the View class constructor.
+	 *
+	 * @group laravel
+	 */
+	public function testDataIsSetOnViewByConstructor()
+	{
+		$view = new View('home.index', array('name' => 'Taylor'));
+
+		$this->assertEquals('Taylor', $view->data['name']);
+	}
+
+	/**
+	 * Test the View::name method.
+	 *
+	 * @group laravel
+	 */
+	public function testNameMethodRegistersAViewName()
+	{
+		View::name('home.index', 'home');
+
+		$this->assertEquals('home.index', View::$names['home']);
+	}
+
+	/**
+	 * Test the View::shared method.
+	 *
+	 * @group laravel
+	 */
+	public function testSharedMethodAddsDataToSharedArray()
+	{
+		View::share('comment', 'Taylor');
+
+		$this->assertEquals('Taylor', View::$shared['comment']);
+	}
+
+	/**
+	 * Test the View::with method.
+	 *
+	 * @group laravel
+	 */
+	public function testViewDataCanBeSetUsingWithMethod()
+	{
+		$view = View::make('home.index')->with('comment', 'Taylor');
+
+		$this->assertEquals('Taylor', $view->data['comment']);
+	}
+
+	/**
+	 * Test the View class constructor.
+	 *
+	 * @group laravel
+	 */
+	public function testEmptyMessageContainerSetOnViewWhenNoErrorsInSession()
+	{
+		$view = new View('home.index');
+
+		$this->assertInstanceOf('Laravel\\Messages', $view->data['errors']);
+	}
+
+	/**
+	 * Test the View __set method.
+	 *
+	 * @group laravel
+	 */
+	public function testDataCanBeSetOnViewsThroughMagicMethods()
+	{
+		$view = new View('home.index');
+
+		$view->comment = 'Taylor';
+
+		$this->assertEquals('Taylor', $view->data['comment']);
+	}
+
+	/**
+	 * Test the View __get method.
+	 *
+	 * @group laravel
+	 */
+	public function testDataCanBeRetrievedFromViewsThroughMagicMethods()
+	{
+		$view = new View('home.index');
+
+		$view->comment = 'Taylor';
+
+		$this->assertEquals('Taylor', $view->comment);
+	}
+
+	/**
+	 * Test the View's ArrayAccess implementation.
+	 *
+	 * @group laravel
+	 */
+	public function testDataCanBeSetOnTheViewThroughArrayAccess()
+	{
+		$view = new View('home.index');
+
+		$view['comment'] = 'Taylor';
+
+		$this->assertEquals('Taylor', $view->data['comment']);
+	}
+
+	/**
+	 * Test the View's ArrayAccess implementation.
+	 *
+	 * @group laravel
+	 */
+	public function testDataCanBeRetrievedThroughArrayAccess()
+	{
+		$view = new View('home.index');
+
+		$view['comment'] = 'Taylor';
+
+		$this->assertEquals('Taylor', $view['comment']);
+	}
+
+	/**
+	 * Test the View::nest method.
+	 *
+	 * @group laravel
+	 */
+	public function testNestMethodSetsViewInstanceInData()
+	{
+		$view = View::make('home.index')->nest('partial', 'tests.basic');
+
+		$this->assertEquals('tests.basic', $view->data['partial']->view);
+
+		$this->assertInstanceOf('Laravel\\View', $view->data['partial']);
+	}
+
+	/**
+	 * Test that the registered data is passed to the view correctly.
+	 *
+	 * @group laravel
+	 */
+	public function testDataIsPassedToViewCorrectly()
+	{
+		View::share('name', 'Taylor');
+
+		$view = View::make('tests.basic')->with('age', 25)->render();
+
+		$this->assertEquals('Taylor is 25', $view);
+	}
+
+	/**
+	 * Test that the View class renders nested views.
+	 *
+	 * @group laravel
+	 */
+	public function testNestedViewsAreRendered()
+	{
+		$view = View::make('tests.basic')
+								->with('age', 25)
+								->nest('name', 'tests.nested');
+
+		$this->assertEquals('Taylor is 25', $view->render());
+	}
+
+	/**
+	 * Test that the View class renders nested responses.
+	 *
+	 * @group laravel
+	 */
+	public function testNestedResponsesAreRendered()
+	{
+		$view = View::make('tests.basic')
+								->with('age', 25)
+								->with('name', Response::view('tests.nested'));
+
+		$this->assertEquals('Taylor is 25', $view->render());
+	}
+
+	/**
+	 * Test the View class raises a composer event.
+	 *
+	 * @group laravel
+	 */
+	public function testComposerEventIsCalledWhenViewIsRendering()
+	{
+		View::composer('tests.basic', function($view)
+		{
+			$view->data = array('name' => 'Taylor', 'age' => 25);
+		});
+
+		$view = View::make('tests.basic')->render();
+
+		$this->assertEquals('Taylor is 25', $view);
+	}
+
+}

+ 32 - 0
laravel/tests/phpunit.php

@@ -0,0 +1,32 @@
+<?php
+
+// --------------------------------------------------------------
+// Define the directory separator for the environment.
+// --------------------------------------------------------------
+define('DS', DIRECTORY_SEPARATOR);
+
+// --------------------------------------------------------------
+// Set the core Laravel path constants.
+// --------------------------------------------------------------
+require 'paths.php';
+
+// --------------------------------------------------------------
+// Override the application paths when testing the core.
+// --------------------------------------------------------------
+$path = path('sys').'tests'.DS;
+
+set_path('app', $path.'application'.DS);
+
+set_path('bundle', $path.'bundles'.DS);
+
+set_path('storage', $path.'storage'.DS);
+
+// --------------------------------------------------------------
+// Bootstrap the Laravel core.
+// --------------------------------------------------------------
+require path('sys').'core.php';
+
+// --------------------------------------------------------------
+// Start the default bundle.
+// --------------------------------------------------------------
+Laravel\Bundle::start(DEFAULT_BUNDLE);

+ 0 - 0
laravel/tests/storage/cache/.gitignore


BIN
laravel/tests/storage/database/application.sqlite


Some files were not shown because too many files changed in this diff