screw-unit 0.3.3 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. data/CHANGES +10 -0
  2. data/Rakefile +27 -25
  3. data/VERSION.yml +4 -0
  4. data/bin/screw_unit_server +14 -4
  5. data/core/EXAMPLE.html +1 -1
  6. data/core/example/spec/suite.html +1 -1
  7. data/core/lib/jquery-1.3.2.js +4376 -0
  8. data/core/lib/jquery.fn.js +2 -1
  9. data/core/lib/screw.behaviors.js +8 -7
  10. data/core/lib/screw.builder.js +34 -19
  11. data/core/lib/screw.css +1 -1
  12. data/core/lib/screw.events.js +5 -5
  13. data/core/lib/screw.matchers.js +59 -2
  14. data/core/spec/suite.html +2 -1
  15. data/core/spec/with_screw_context_spec.js +9 -0
  16. data/lib/screw_unit.rb +13 -16
  17. data/lib/screw_unit/representations.rb +2 -0
  18. data/lib/screw_unit/{resources/spec.rb → representations/spec.html.rb} +55 -39
  19. data/spec/functional/functional_spec.rb +1 -1
  20. data/spec/functional/functional_spec_helper.rb +21 -33
  21. data/spec/functional/functional_spec_server_starter.rb +68 -0
  22. data/spec/unit/js_test_core/specs/spec_file_spec.rb +52 -18
  23. data/spec/unit/unit_spec_helper.rb +24 -91
  24. data/vendor/js-test-core/CHANGES +8 -0
  25. data/vendor/js-test-core/Rakefile +1 -0
  26. data/vendor/js-test-core/lib/js_test_core.rb +22 -14
  27. data/vendor/js-test-core/lib/js_test_core/app.rb +12 -0
  28. data/vendor/js-test-core/lib/js_test_core/client.rb +21 -9
  29. data/vendor/js-test-core/lib/js_test_core/configuration.rb +35 -0
  30. data/vendor/js-test-core/lib/js_test_core/extensions.rb +1 -1
  31. data/vendor/js-test-core/lib/js_test_core/extensions/selenium/client/driver.rb +7 -0
  32. data/vendor/js-test-core/lib/js_test_core/models.rb +8 -0
  33. data/vendor/js-test-core/lib/js_test_core/models/selenium_session.rb +80 -0
  34. data/vendor/js-test-core/lib/js_test_core/representations.rb +11 -0
  35. data/vendor/js-test-core/lib/js_test_core/representations/dir.html.rb +24 -0
  36. data/vendor/js-test-core/lib/js_test_core/representations/not_found.html.rb +15 -0
  37. data/vendor/js-test-core/lib/js_test_core/representations/page.html.rb +41 -0
  38. data/vendor/js-test-core/lib/js_test_core/representations/spec.html.rb +24 -0
  39. data/vendor/js-test-core/lib/js_test_core/resources.rb +13 -7
  40. data/vendor/js-test-core/lib/js_test_core/resources/core_file.rb +19 -0
  41. data/vendor/js-test-core/lib/js_test_core/resources/file.rb +42 -20
  42. data/vendor/js-test-core/lib/js_test_core/resources/implementations_deprecation.rb +12 -0
  43. data/vendor/js-test-core/lib/js_test_core/resources/not_found.rb +35 -0
  44. data/vendor/js-test-core/lib/js_test_core/resources/resource.rb +16 -0
  45. data/vendor/js-test-core/lib/js_test_core/resources/selenium_session.rb +104 -0
  46. data/vendor/js-test-core/lib/js_test_core/resources/spec_file.rb +63 -0
  47. data/vendor/js-test-core/lib/js_test_core/resources/web_root.rb +5 -60
  48. data/vendor/js-test-core/{vendor/thin-rest/README → spec/example_core/subdir/SubDirFile.js} +0 -0
  49. data/vendor/js-test-core/spec/example_specs/custom_dir_and_suite/passing_spec.js +6 -0
  50. data/vendor/js-test-core/spec/example_specs/custom_suite.html +8 -0
  51. data/vendor/js-test-core/spec/example_specs/foo/failing_spec.js +1 -1
  52. data/vendor/js-test-core/spec/example_specs/foo/passing_spec.js +1 -1
  53. data/vendor/js-test-core/spec/spec_helpers/be_http.rb +32 -0
  54. data/vendor/js-test-core/spec/spec_helpers/example_group.rb +36 -0
  55. data/vendor/js-test-core/spec/spec_helpers/fake_selenium_driver.rb +27 -0
  56. data/vendor/js-test-core/spec/spec_helpers/show_test_exceptions.rb +22 -0
  57. data/vendor/js-test-core/spec/unit/js_test_core/client_spec.rb +35 -10
  58. data/vendor/js-test-core/spec/unit/js_test_core/configuration_spec.rb +44 -0
  59. data/vendor/js-test-core/spec/unit/js_test_core/models/selenium_session_spec.rb +85 -0
  60. data/vendor/js-test-core/spec/unit/js_test_core/resources/core_file_spec.rb +60 -0
  61. data/vendor/js-test-core/spec/unit/js_test_core/resources/file_spec.rb +54 -63
  62. data/vendor/js-test-core/spec/unit/js_test_core/resources/implementations_deprecation_spec.rb +18 -0
  63. data/vendor/js-test-core/spec/unit/js_test_core/resources/not_found_spec.rb +51 -0
  64. data/vendor/js-test-core/spec/unit/js_test_core/resources/selenium_session_spec.rb +362 -0
  65. data/vendor/js-test-core/spec/unit/js_test_core/resources/spec_file_spec.rb +120 -0
  66. data/vendor/js-test-core/spec/unit/js_test_core/resources/web_root_spec.rb +15 -19
  67. data/vendor/js-test-core/spec/unit/unit_spec_helper.rb +16 -149
  68. data/vendor/js-test-core/vendor/lucky-luciano/README.markdown +7 -0
  69. data/vendor/js-test-core/vendor/lucky-luciano/lib/lucky_luciano.rb +4 -0
  70. data/vendor/js-test-core/vendor/lucky-luciano/lib/lucky_luciano/resource.rb +135 -0
  71. data/vendor/js-test-core/vendor/lucky-luciano/lib/lucky_luciano/rspec.rb +4 -0
  72. data/vendor/js-test-core/vendor/lucky-luciano/lib/lucky_luciano/rspec/be_http.rb +32 -0
  73. data/vendor/js-test-core/vendor/lucky-luciano/spec/lucky_luciano/resource_spec.rb +231 -0
  74. data/vendor/js-test-core/vendor/lucky-luciano/spec/spec_helper.rb +48 -0
  75. data/vendor/js-test-core/vendor/{thin-rest → lucky-luciano}/spec/spec_suite.rb +1 -2
  76. metadata +134 -145
  77. data/core/lib/jquery-1.2.6.js +0 -3549
  78. data/lib/screw_unit/resources.rb +0 -2
  79. data/spec/unit/js_test_core/specs/spec_dir_spec.rb +0 -38
  80. data/vendor/js-test-core/lib/js_test_core/rack.rb +0 -2
  81. data/vendor/js-test-core/lib/js_test_core/rack/commonlogger.rb +0 -5
  82. data/vendor/js-test-core/lib/js_test_core/rails_server.rb +0 -22
  83. data/vendor/js-test-core/lib/js_test_core/resources/dir.rb +0 -67
  84. data/vendor/js-test-core/lib/js_test_core/resources/file_not_found.rb +0 -11
  85. data/vendor/js-test-core/lib/js_test_core/resources/runner.rb +0 -107
  86. data/vendor/js-test-core/lib/js_test_core/resources/session.rb +0 -44
  87. data/vendor/js-test-core/lib/js_test_core/resources/session_finish.rb +0 -17
  88. data/vendor/js-test-core/lib/js_test_core/resources/specs/spec_dir.rb +0 -46
  89. data/vendor/js-test-core/lib/js_test_core/resources/specs/spec_file.rb +0 -17
  90. data/vendor/js-test-core/lib/js_test_core/selenium.rb +0 -2
  91. data/vendor/js-test-core/lib/js_test_core/selenium/selenium_driver.rb +0 -5
  92. data/vendor/js-test-core/lib/js_test_core/server.rb +0 -50
  93. data/vendor/js-test-core/lib/js_test_core/thin.rb +0 -3
  94. data/vendor/js-test-core/lib/js_test_core/thin/backends/js_test_core_server.rb +0 -9
  95. data/vendor/js-test-core/lib/js_test_core/thin/js_test_core_connection.rb +0 -8
  96. data/vendor/js-test-core/spec/unit/js_test_core/rails_server_spec.rb +0 -45
  97. data/vendor/js-test-core/spec/unit/js_test_core/resources/dir_spec.rb +0 -52
  98. data/vendor/js-test-core/spec/unit/js_test_core/resources/file_not_found_spec.rb +0 -16
  99. data/vendor/js-test-core/spec/unit/js_test_core/resources/runners/runner_spec.rb +0 -303
  100. data/vendor/js-test-core/spec/unit/js_test_core/resources/session_finish_spec.rb +0 -79
  101. data/vendor/js-test-core/spec/unit/js_test_core/resources/session_spec.rb +0 -82
  102. data/vendor/js-test-core/spec/unit/js_test_core/resources/specs/spec_dir_spec.rb +0 -105
  103. data/vendor/js-test-core/spec/unit/js_test_core/resources/specs/spec_file_spec.rb +0 -42
  104. data/vendor/js-test-core/spec/unit/js_test_core/server_spec.rb +0 -117
  105. data/vendor/js-test-core/spec/unit/thin/js_test_core_connection_spec.rb +0 -6
  106. data/vendor/js-test-core/vendor/thin-rest/CHANGES +0 -2
  107. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest.rb +0 -9
  108. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/connection.rb +0 -116
  109. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/extensions.rb +0 -3
  110. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/extensions/object.rb +0 -21
  111. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/resource.rb +0 -108
  112. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/resource_invalid.rb +0 -4
  113. data/vendor/js-test-core/vendor/thin-rest/lib/thin_rest/routing_error.rb +0 -5
  114. data/vendor/js-test-core/vendor/thin-rest/spec/thin_rest/connection_spec.rb +0 -207
  115. data/vendor/js-test-core/vendor/thin-rest/spec/thin_rest/resource_spec.rb +0 -127
  116. data/vendor/js-test-core/vendor/thin-rest/spec/thin_rest_spec_helper.rb +0 -124
@@ -3,29 +3,25 @@ require File.expand_path("#{File.dirname(__FILE__)}/../../unit_spec_helper")
3
3
  module JsTestCore
4
4
  module Resources
5
5
  describe WebRoot do
6
- attr_reader :web_root
7
- before(:each) do
8
- @web_root = WebRoot.new(:connection => connection, :public_path => public_path)
9
- end
10
-
11
- describe "GET /stylesheets" do
12
- it "returns a page with a of files in the directory" do
13
- mock(connection).send_head()
14
- mock(connection).send_body(Regexp.new('<a href="example.css">example.css</a>'))
15
-
16
- connection.receive_data("GET /stylesheets HTTP/1.1\r\nHost: _\r\n\r\n")
6
+ macro("includes a link to the spec suite") do |relative_path|
7
+ it "includes a link to the spec suite" do
8
+ response = get(relative_path)
9
+ response.should be_http(
10
+ 200,
11
+ {},
12
+ ""
13
+ )
14
+ doc = Nokogiri::HTML(response.body)
15
+ doc.css("a[href='/specs']").should_not be_nil
17
16
  end
18
17
  end
19
18
 
20
- describe "GET /stylesheets/example.css" do
21
- it "returns a page with a of files in the directory" do
22
- path = "#{public_path}/stylesheets/example.css"
23
- mock(connection).send_head(200, 'Content-Type' => "text/css", 'Content-Length' => ::File.size(path), 'Last-Modified' => ::File.mtime(path).rfc822)
24
- mock(connection).send_data(::File.read(path))
25
- stub(EventMachine).close_connection
19
+ describe "GET " do
20
+ send("includes a link to the spec suite", "")
21
+ end
26
22
 
27
- connection.receive_data("GET /stylesheets/example.css HTTP/1.1\r\nHost: _\r\n\r\n")
28
- end
23
+ describe "GET /" do
24
+ send("includes a link to the spec suite", "/")
29
25
  end
30
26
  end
31
27
  end
@@ -1,161 +1,28 @@
1
1
  require "rubygems"
2
2
  require "spec"
3
+ require "spec/autorun"
4
+ require "rack/test"
5
+ ARGV.push("-b")
3
6
 
4
7
  dir = File.dirname(__FILE__)
5
- $LOAD_PATH.unshift File.expand_path("#{dir}/../../lib")
8
+ LIBRARY_ROOT_DIR = File.expand_path("#{dir}/../..")
9
+ $LOAD_PATH.unshift File.expand_path("#{LIBRARY_ROOT_DIR}/lib")
6
10
  require "js_test_core"
7
- require "hpricot"
11
+ require "nokogiri"
8
12
  require "guid"
13
+ require "#{LIBRARY_ROOT_DIR}/spec/spec_helpers/be_http"
14
+ require "#{LIBRARY_ROOT_DIR}/spec/spec_helpers/example_group"
15
+ require "#{LIBRARY_ROOT_DIR}/spec/spec_helpers/fake_selenium_driver"
16
+ require "#{LIBRARY_ROOT_DIR}/spec/spec_helpers/show_test_exceptions"
9
17
 
10
18
  Spec::Runner.configure do |config|
11
19
  config.mock_with :rr
12
20
  end
13
21
 
14
- module Spec
15
- module Matchers
16
- class Exist
17
- def matches?(actual)
18
- @actual = actual
19
- !@actual.nil?
20
- end
21
- end
22
- end
23
- end
24
-
25
- class JsTestCoreTestDir < JsTestCore::Resources::Dir
26
- def get
27
-
28
- end
29
- end
30
-
31
- class Spec::ExampleGroup
32
- class << self
33
- def thin_logging
34
- @thin_logging = true if @thin_logging.nil?
35
- @thin_logging
36
- end
37
-
38
- attr_writer :thin_logging
39
- end
40
-
41
- attr_reader :core_path, :spec_root_path, :implementation_root_path, :public_path, :server, :connection
42
- before(:all) do
43
- dir = File.dirname(__FILE__)
44
- @core_path = File.expand_path("#{dir}/../example_core")
45
- JsTestCore.core_path = core_path
46
- @spec_root_path = File.expand_path("#{dir}/../example_specs")
47
- @implementation_root_path = File.expand_path("#{dir}/../example_public/javascripts")
48
- @public_path = File.expand_path("#{dir}/../example_public")
49
- stub(Thread).start.yields
50
- end
51
-
52
- before(:each) do
53
- JsTestCore::Server.instance = JsTestCore::Server.new(spec_root_path, implementation_root_path, public_path)
54
- stub(EventMachine).run do
55
- raise "You need to mock calls to EventMachine.run or the process will hang"
56
- end
57
- stub(EventMachine).start_server do
58
- raise "You need to mock calls to EventMachine.start_server or the process will hang"
59
- end
60
- stub(EventMachine).send_data do
61
- raise "Calls to EventMachine.send_data must be mocked or stubbed"
62
- end
63
- @connection = create_connection
64
- stub(EventMachine).send_data {raise "EventMachine.send_data must be handled"}
65
- stub(EventMachine).close_connection {raise "EventMachine.close_connection must be handled"}
66
- @server = JsTestCore::Server.instance
67
- Thin::Logging.silent = !self.class.thin_logging
68
- Thin::Logging.debug = self.class.thin_logging
69
- end
70
-
71
- after(:each) do
72
- JsTestCore::Resources::WebRoot.dispatch_strategy = nil
73
- Thin::Logging.silent = true
74
- Thin::Logging.debug = false
75
- end
76
-
77
- def create_connection(guid=Guid.new)
78
- Thin::JsTestCoreConnection.new(Guid.new)
79
- end
80
-
81
- def get(url, params={})
82
- request(:get, url, params)
83
- end
84
-
85
- def post(url, params={})
86
- request(:post, url, params)
87
- end
88
-
89
- def put(url, params={})
90
- request(:put, url, params)
91
- end
92
-
93
- def delete(url, params={})
94
- request(:delete, url, params)
95
- end
96
-
97
- def env_for(method, url, params)
98
- Rack::MockRequest.env_for(url, params.merge({:method => method.to_s.upcase, 'js_test_core.connection' => connection}))
99
- end
22
+ Sinatra::Application.use ShowTestExceptions
23
+ Sinatra::Application.set :raise_errors, true
24
+ Sinatra::Application.set :show_exceptions, false
25
+ JsTestCore::App.set :raise_errors, true
26
+ JsTestCore::App.set :show_exceptions, false
100
27
 
101
- def create_request(method, path, params={})
102
- body = params.map do |key, value|
103
- "#{URI.escape(key)}=#{URI.escape(value)}"
104
- end.join("&")
105
- connection.receive_data "#{method.to_s.upcase} #{path} HTTP/1.1\r\nHost: _\r\nContent-Length: #{body.length}\r\n\r\n#{body}"
106
- connection.response
107
- end
108
- alias_method :request, :create_request
109
-
110
- def spec_dir(relative_path="")
111
- absolute_path = spec_root_path + relative_path
112
- JsTestCore::Resources::Specs::SpecDir.new(:connection => connection, :absolute_path => absolute_path, :relative_path => "/specs#{relative_path}")
113
- end
114
-
115
- def contain_spec_file_with_correct_paths(path_relative_to_spec_root)
116
- expected_absolute_path = spec_root_path + path_relative_to_spec_root
117
- expected_relative_path = "/specs" + path_relative_to_spec_root
118
-
119
- ::Spec::Matchers::SimpleMatcher.new(expected_relative_path) do |globbed_files|
120
- file = globbed_files.find do |file|
121
- file.absolute_path == expected_absolute_path
122
- end
123
- raise "Did not find file with absolute path of #{expected_absolute_path.inspect}" unless file
124
- file.relative_path == expected_relative_path
125
- end
126
- end
127
-
128
- def stub_send_data
129
- stub(EventMachine).send_data do |signature, data, data_length|
130
- data_length
131
- end
132
- end
133
- end
134
-
135
- class FakeSeleniumDriver
136
- SESSION_ID = "DEADBEEF"
137
- attr_reader :session_id
138
-
139
- def initialize
140
- @session_id = nil
141
- end
142
-
143
- def start
144
- @session_id = SESSION_ID
145
- end
146
-
147
- def stop
148
- @session_id = nil
149
- end
150
-
151
- def open(url)
152
- end
153
-
154
- def create_cookie(key_value, options="")
155
-
156
- end
157
-
158
- def session_started?
159
- !!@session_id
160
- end
161
- end
28
+ Sinatra::Application.use(JsTestCore::App)
@@ -0,0 +1,7 @@
1
+ Lucky Luciano, is a library that makes it easy to organize your Sinatra routes into Restful Resources.
2
+
3
+ ## Who was this Lucky Luciano person?
4
+
5
+ Lucky Luciano was a mob boss and an alleged friend of Frank Sinatra.
6
+
7
+ http://news.bbc.co.uk/2/hi/special_report/1998/05/98/sinatra/94360.stm
@@ -0,0 +1,4 @@
1
+ require "sinatra/base"
2
+
3
+ dir = File.dirname(__FILE__)
4
+ require "#{dir}/lucky_luciano/resource"
@@ -0,0 +1,135 @@
1
+ module LuckyLuciano
2
+ class Resource
3
+ class << self
4
+ attr_reader :base_path_definition
5
+
6
+ def map(base_path_definition)
7
+ @base_path_definition = base_path_definition
8
+ end
9
+
10
+ def recorded_http_handlers
11
+ @recorded_http_handlers ||= []
12
+ end
13
+
14
+ def route_handler
15
+ create_sinatra_handler
16
+ end
17
+
18
+ ["get", "put", "post", "delete"].each do |http_verb|
19
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
20
+ def #{http_verb}(relative_path, opts={}, &block)
21
+ recorded_http_handlers << [:#{http_verb}, relative_path, opts, block]
22
+ end
23
+ RUBY
24
+ end
25
+
26
+ def path(*sub_paths)
27
+ params = sub_paths.last.is_a?(Hash) ? sub_paths.pop : {}
28
+
29
+ sub_path_definition = sub_paths.join("/")
30
+
31
+ full_path = "#{base_path(params)}/#{path_from_definition(sub_path_definition, params)}".
32
+ gsub("//", "/").gsub(/\/$/, "")
33
+
34
+ base_path_param_keys = param_keys_from(base_path_definition)
35
+ query_params = params.delete_if do |key, value|
36
+ base_path_param_keys.include?(key)
37
+ end
38
+
39
+ sub_path_param_keys = param_keys_from(sub_path_definition)
40
+ query_params = params.delete_if do |key, value|
41
+ sub_path_param_keys.include?(key)
42
+ end
43
+
44
+ if query_params.empty?
45
+ full_path
46
+ else
47
+ query = build_query(query_params)
48
+ "#{full_path}?#{query}"
49
+ end
50
+ end
51
+
52
+ def base_path(params={})
53
+ path_from_definition(base_path_definition, params)
54
+ end
55
+
56
+ protected
57
+
58
+ def path_from_definition(definition, params={})
59
+ param_keys = param_keys_from(definition)
60
+ if param_keys.empty?
61
+ definition.dup
62
+ else
63
+ param_keys.each do |base_path_param|
64
+ unless params.include?(base_path_param.to_sym)
65
+ raise ArgumentError, "Expected #{base_path_param.inspect} to have a value"
66
+ end
67
+ end
68
+ definition.split("/").map do |segment|
69
+ if param_key = segment_param_key(segment)
70
+ params[param_key]
71
+ else
72
+ segment
73
+ end
74
+ end.join("/")
75
+ end
76
+ end
77
+
78
+ def param_keys_from(definition)
79
+ definition.split("/").find_all do |segment|
80
+ segment_param_key(segment)
81
+ end.map do |param|
82
+ param[1..-1].to_sym
83
+ end
84
+ end
85
+
86
+ def segment_param_key(segment)
87
+ segment[0..0] == ':' ? segment[1..-1].to_sym : nil
88
+ end
89
+
90
+ def build_query(params)
91
+ params.to_a.inject([]) do |splatted_params, (key, value)|
92
+ [value].flatten.each do |value_in_param|
93
+ splatted_params << "#{URI.escape(key.to_s)}=#{URI.escape(value_in_param.to_s)}"
94
+ end
95
+ splatted_params
96
+ end.join("&")
97
+ end
98
+
99
+ def create_sinatra_handler
100
+ handlers = recorded_http_handlers
101
+ resource_class = self
102
+ Module.new do
103
+ (class << self; self; end).class_eval do
104
+ define_method(:registered) do |app|
105
+ handlers.each do |handler|
106
+ verb, relative_path, opts, block = handler
107
+ full_path = "#{resource_class.base_path_definition}/#{relative_path}".
108
+ gsub("//", "/").gsub(%r{^.+/$}) do |match|
109
+ match.gsub(%r{/$}, "")
110
+ end
111
+ app.send(verb, full_path, opts) do
112
+ resource_class.new(self).instance_eval(&block)
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ attr_reader :app
122
+
123
+ def initialize(app)
124
+ @app = app
125
+ end
126
+
127
+ def method_missing(method_name, *args, &block)
128
+ if app.respond_to?(method_name)
129
+ app.send(method_name, *args, &block)
130
+ else
131
+ super
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,4 @@
1
+ dir = File.dirname(__FILE__)
2
+ Dir["#{dir}/rspec/**/*.rb"].each do |file|
3
+ require file
4
+ end
@@ -0,0 +1,32 @@
1
+ module BeHttp
2
+ include Spec::Matchers
3
+ def be_http(status, headers, body)
4
+ SimpleMatcher.new(nil) do |given, matcher|
5
+ description = (<<-DESC).gsub(/^ +/, "")
6
+ be an http of
7
+ expected status: #{status.inspect}
8
+ actual status : #{given.status.inspect}
9
+
10
+ expected headers containing: #{headers.inspect}
11
+ actual headers : #{given.headers.inspect}
12
+
13
+ expected body containing: #{body.inspect}
14
+ actual body : #{given.body.inspect}
15
+ DESC
16
+ matcher.failure_message = description
17
+ matcher.negative_failure_message = "not #{description}"
18
+
19
+ passed = true
20
+ unless given.status == status
21
+ passed = false
22
+ end
23
+ unless headers.all?{|k, v| given.headers[k] == headers[k]}
24
+ passed = false
25
+ end
26
+ unless body.is_a?(Regexp) ? given.body =~ body : given.body.include?(body)
27
+ passed = false
28
+ end
29
+ passed
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,231 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper")
2
+
3
+ module LuckyLuciano
4
+ module ResourceSpec
5
+ class Root < Resource
6
+ map "/"
7
+ end
8
+
9
+ class ResourceFixture < Resource
10
+ map "/foobar"
11
+ end
12
+
13
+ class ResourceFixtureWithSubPaths < Resource
14
+ map "/foobar"
15
+
16
+ get "/baz" do
17
+ "Response from /foobar/baz"
18
+ end
19
+
20
+ get "/users/:user_id" do
21
+ "User id is #{params[:user_id]}"
22
+ end
23
+ end
24
+
25
+ class User < Resource
26
+ map "/users/:user_id"
27
+
28
+ get "/friends" do
29
+ "User #{params['user_id']} friends"
30
+ end
31
+ end
32
+
33
+ describe Resource do
34
+ include ResourceSpec
35
+
36
+ before do
37
+ ResourceFixture.recorded_http_handlers.clear
38
+ end
39
+
40
+ macro("http verb") do |verb|
41
+ describe ".#{verb}" do
42
+ context "" do
43
+ before do
44
+ ResourceFixture.send(verb, "/") do
45
+ "He sleeps with the fishes"
46
+ end
47
+ end
48
+
49
+ it "creates a route to #{verb.upcase} the given path that executes the given block" do
50
+ app.register(ResourceFixture.route_handler)
51
+ response = send(verb, "/foobar")
52
+ response.should be_http(
53
+ 200,
54
+ {},
55
+ "He sleeps with the fishes"
56
+ )
57
+ end
58
+ end
59
+
60
+ context "when the base path is blank and the relative path is blank" do
61
+ before do
62
+ Root.send(verb, "") do
63
+ "Response from /"
64
+ end
65
+ end
66
+
67
+ it "creates a route to /" do
68
+ app.register(Root.route_handler)
69
+ response = send(verb, "/")
70
+ response.should be_http(
71
+ 200,
72
+ {},
73
+ "Response from /"
74
+ )
75
+ end
76
+ end
77
+
78
+ context "when the relative path does not have a leading slash" do
79
+ before do
80
+ ResourceFixtureWithSubPaths.send(verb, "no_leading_slash") do
81
+ "Response from /foobar/no_leading_slash"
82
+ end
83
+ end
84
+
85
+ it "creates a route to #{verb.upcase} the given path that executes the given block" do
86
+ app.register(ResourceFixtureWithSubPaths.route_handler)
87
+ response = send(verb, "/foobar/no_leading_slash")
88
+ response.should be_http(
89
+ 200,
90
+ {},
91
+ "Response from /foobar/no_leading_slash"
92
+ )
93
+ end
94
+ end
95
+
96
+
97
+ it "does not respond to another type of http request" do
98
+ ResourceFixture.send(verb, "/") do
99
+ ""
100
+ end
101
+ app.register(ResourceFixture.route_handler)
102
+ get("/foobar").status.should == 404 unless verb == "get"
103
+ put("/foobar").status.should == 404 unless verb == "put"
104
+ post("/foobar").status.should == 404 unless verb == "post"
105
+ delete("/foobar").status.should == 404 unless verb == "delete"
106
+ end
107
+
108
+ describe "Instance behavior" do
109
+ attr_reader :evaluation_target
110
+ before do
111
+ evaluation_target = nil
112
+ ResourceFixture.send(verb, "/") do
113
+ evaluation_target = self
114
+ ""
115
+ end
116
+ app.register(ResourceFixture.route_handler)
117
+
118
+ send(verb, "/foobar")
119
+ @evaluation_target = evaluation_target
120
+ end
121
+
122
+ it "evaluates the block in as a Resource" do
123
+ evaluation_target.class.should == ResourceFixture
124
+ end
125
+
126
+ it "sets app to be the Sinatra context" do
127
+ evaluation_target.app.class.should == Sinatra::Application
128
+ end
129
+
130
+ it "delegates methods to the #app" do
131
+ return_value = nil
132
+ mock.proxy(evaluation_target.app).params {|val| return_value = val}
133
+ evaluation_target.params.should == return_value
134
+ end
135
+
136
+ context "when the #app does not respond to the method" do
137
+ it "raises a NoMethodError from the Resource's perspective" do
138
+ lambda do
139
+ evaluation_target.i_dont_exist
140
+ end.should raise_error(NoMethodError, /ResourceFixture/)
141
+ end
142
+ end
143
+ end
144
+
145
+ end
146
+ end
147
+
148
+ send("http verb", "get")
149
+ send("http verb", "put")
150
+ send("http verb", "post")
151
+ send("http verb", "delete")
152
+
153
+ describe ".path" do
154
+ context "when passed nothing" do
155
+ it "returns the base_path" do
156
+ ResourceFixture.path.should == "/foobar"
157
+ end
158
+ end
159
+
160
+ context "when passed a sub path" do
161
+ it "merges the base_path into the sub path, regardless of a / in front" do
162
+ ResourceFixtureWithSubPaths.path("/baz").should == "/foobar/baz"
163
+ ResourceFixtureWithSubPaths.path("baz").should == "/foobar/baz"
164
+ end
165
+
166
+ context "when passed a multiple sub paths" do
167
+ it "joins the sub paths with '/'" do
168
+ ResourceFixtureWithSubPaths.path("users", 99).should == "/foobar/users/99"
169
+ end
170
+ end
171
+
172
+ context "when passed a hash as the last argument" do
173
+ context "when using a single path argument" do
174
+ it "creates url params from the hash" do
175
+ path = ResourceFixtureWithSubPaths.path(
176
+ "/users/:user_id", {:user_id => 99, :single_value_param => "single_value_param_value", 'multiple_value_param[]' => [1,2,3]}
177
+ )
178
+ uri = URI.parse(path)
179
+ uri.path.should == "/foobar/users/99"
180
+ query_parts = uri.query.split("&")
181
+ query_parts.should =~ [
182
+ "multiple_value_param[]=1",
183
+ "multiple_value_param[]=2",
184
+ "multiple_value_param[]=3",
185
+ "single_value_param=single_value_param_value",
186
+ ]
187
+ end
188
+ end
189
+
190
+ context "when using multiple path arguments" do
191
+ it "creates url params from the hash" do
192
+ path = ResourceFixtureWithSubPaths.path(
193
+ "users", 99, {:single_value_param => "single_value_param_value", 'multiple_value_param[]' => [1,2,3]}
194
+ )
195
+ uri = URI.parse(path)
196
+ uri.path.should == "/foobar/users/99"
197
+ query_parts = uri.query.split("&")
198
+ query_parts.should =~ [
199
+ "multiple_value_param[]=1",
200
+ "multiple_value_param[]=2",
201
+ "multiple_value_param[]=3",
202
+ "single_value_param=single_value_param_value",
203
+ ]
204
+ end
205
+ end
206
+ end
207
+ end
208
+
209
+ context "when the base_path contains a parameter" do
210
+ context "when not passed" do
211
+ it "raises an ArgumentError" do
212
+ lambda do
213
+ User.path
214
+ end.should raise_error(
215
+ ArgumentError,
216
+ %r{Expected :user_id to have a value}
217
+ )
218
+ end
219
+ end
220
+
221
+ context "when first argument is a hash" do
222
+ it "returns the full path with the base path param value" do
223
+ User.path("friends", :user_id => 99).should == "/users/99/friends"
224
+ end
225
+ end
226
+ end
227
+ end
228
+ end
229
+ end
230
+
231
+ end