btakita-screw-unit-server 0.3.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. data/CHANGES +44 -1
  2. data/README.markdown +17 -5
  3. data/Rakefile +28 -55
  4. data/VERSION.yml +5 -0
  5. data/bin/screw_unit_server +8 -4
  6. data/core/CHANGES +10 -0
  7. data/core/EXAMPLE.html +4 -4
  8. data/core/README.markdown +7 -7
  9. data/core/example/models/man.js +2 -2
  10. data/core/example/spec/suite.html +1 -1
  11. data/core/lib/jquery-1.3.2.js +4376 -0
  12. data/core/lib/jquery.fn.js +2 -1
  13. data/core/lib/jquery.print.js +13 -12
  14. data/core/lib/screw.behaviors.js +11 -9
  15. data/core/lib/screw.builder.js +26 -11
  16. data/core/lib/screw.css +2 -2
  17. data/core/lib/screw.events.js +11 -4
  18. data/core/lib/screw.matchers.js +192 -13
  19. data/core/spec/behaviors_spec.js +11 -1
  20. data/core/spec/matchers_spec.js +288 -9
  21. data/core/spec/print_spec.js +47 -8
  22. data/core/spec/suite.html +2 -1
  23. data/core/spec/with_screw_context_spec.js +9 -0
  24. data/lib/screw_unit.rb +12 -17
  25. data/spec/functional/functional_spec.rb +15 -4
  26. data/spec/functional/functional_spec_helper.rb +22 -35
  27. data/spec/functional/functional_spec_server_starter.rb +68 -0
  28. data/spec/spec_suite.rb +0 -1
  29. data/standalone.ru +3 -0
  30. data/vendor/js-test-core/CHANGES +22 -0
  31. data/vendor/js-test-core/README +4 -10
  32. data/vendor/js-test-core/Rakefile +2 -1
  33. data/vendor/js-test-core/{spec/example_core/JsTestCore.css → bin/js-test-client} +0 -0
  34. data/vendor/js-test-core/bin/js-test-server +6 -0
  35. data/vendor/js-test-core/lib/js_test_core.rb +27 -19
  36. data/vendor/js-test-core/lib/js_test_core/app.rb +11 -0
  37. data/vendor/js-test-core/lib/js_test_core/client.rb +125 -36
  38. data/vendor/js-test-core/lib/js_test_core/configuration.rb +65 -0
  39. data/vendor/js-test-core/lib/js_test_core/representations.rb +13 -0
  40. data/vendor/js-test-core/lib/js_test_core/representations/dir.html.rb +25 -0
  41. data/vendor/js-test-core/lib/js_test_core/representations/frameworks.rb +3 -0
  42. data/vendor/js-test-core/lib/js_test_core/representations/not_found.html.rb +16 -0
  43. data/vendor/js-test-core/lib/js_test_core/representations/page.html.rb +41 -0
  44. data/vendor/js-test-core/lib/js_test_core/representations/suite.html.rb +57 -0
  45. data/vendor/js-test-core/lib/js_test_core/representations/suites.rb +3 -0
  46. data/vendor/js-test-core/lib/js_test_core/representations/suites/screw_unit.html.rb +81 -0
  47. data/vendor/js-test-core/lib/js_test_core/resources.rb +12 -8
  48. data/vendor/js-test-core/lib/js_test_core/resources/core_file.rb +19 -0
  49. data/vendor/js-test-core/lib/js_test_core/resources/file.rb +43 -13
  50. data/vendor/js-test-core/lib/js_test_core/resources/implementations_deprecation.rb +12 -0
  51. data/vendor/js-test-core/lib/js_test_core/resources/not_found.rb +28 -0
  52. data/vendor/js-test-core/lib/js_test_core/resources/resource.rb +16 -0
  53. data/vendor/js-test-core/lib/js_test_core/resources/spec_file.rb +51 -0
  54. data/vendor/js-test-core/lib/js_test_core/resources/web_root.rb +7 -54
  55. data/vendor/js-test-core/lib/js_test_core/server.rb +65 -92
  56. data/vendor/js-test-core/public/js_test_server.js +541 -0
  57. data/vendor/js-test-core/spec/{example_core/JsTestCore.js → example_framework/JsTestCore.css} +0 -0
  58. data/vendor/js-test-core/spec/{example_public/favicon.ico → example_framework/JsTestCore.js} +0 -0
  59. data/vendor/js-test-core/spec/{example_public/robots.txt → example_framework/subdir/SubDirFile.js} +0 -0
  60. data/vendor/js-test-core/spec/example_root/favicon.ico +0 -0
  61. data/vendor/js-test-core/spec/{example_public → example_root}/javascripts/foo.js +1 -1
  62. data/vendor/js-test-core/spec/example_root/javascripts/large_file.js +59 -0
  63. data/vendor/js-test-core/spec/example_root/javascripts/subdir/bar.js +1 -0
  64. data/vendor/js-test-core/spec/example_root/robots.txt +0 -0
  65. data/vendor/js-test-core/spec/{example_public → example_root}/stylesheets/example.css +0 -0
  66. data/vendor/js-test-core/spec/example_spec/custom_dir_and_suite/passing_spec.js +8 -0
  67. data/vendor/js-test-core/spec/example_spec/custom_suite.html +8 -0
  68. data/vendor/js-test-core/spec/example_spec/failing_spec.js +7 -0
  69. data/vendor/js-test-core/spec/example_spec/foo/failing_spec.js +8 -0
  70. data/vendor/js-test-core/spec/example_spec/foo/passing_spec.js +8 -0
  71. data/vendor/js-test-core/spec/example_spec/passing_spec.js +8 -0
  72. data/vendor/js-test-core/spec/functional/functional_spec.rb +25 -0
  73. data/vendor/js-test-core/spec/functional/functional_spec_helper.rb +42 -0
  74. data/vendor/js-test-core/spec/functional/functional_spec_server_starter.rb +77 -0
  75. data/vendor/js-test-core/spec/functional_suite.rb +10 -0
  76. data/vendor/js-test-core/spec/spec_helpers/be_http.rb +32 -0
  77. data/vendor/js-test-core/spec/spec_helpers/example_group.rb +36 -0
  78. data/vendor/js-test-core/spec/spec_helpers/fake_selenium_driver.rb +16 -0
  79. data/vendor/js-test-core/spec/spec_helpers/show_test_exceptions.rb +22 -0
  80. data/vendor/js-test-core/spec/spec_suite.rb +2 -1
  81. data/vendor/js-test-core/spec/unit/js_test_core/client_spec.rb +153 -94
  82. data/vendor/js-test-core/spec/unit/js_test_core/configuration_spec.rb +50 -0
  83. data/vendor/js-test-core/spec/unit/js_test_core/resources/core_file_spec.rb +60 -0
  84. data/vendor/js-test-core/spec/unit/js_test_core/resources/file_spec.rb +61 -68
  85. data/vendor/js-test-core/spec/unit/js_test_core/resources/implementations_deprecation_spec.rb +18 -0
  86. data/vendor/js-test-core/spec/unit/js_test_core/resources/not_found_spec.rb +51 -0
  87. data/vendor/js-test-core/spec/unit/js_test_core/resources/spec_file_spec.rb +149 -0
  88. data/vendor/js-test-core/spec/unit/js_test_core/resources/web_root_spec.rb +14 -89
  89. data/vendor/js-test-core/spec/unit/js_test_core/server_spec.rb +41 -106
  90. data/vendor/js-test-core/spec/unit/unit_spec_helper.rb +19 -114
  91. data/vendor/js-test-core/standalone.ru +1 -0
  92. data/vendor/js-test-core/vendor/lucky-luciano/README.markdown +77 -0
  93. data/vendor/js-test-core/vendor/lucky-luciano/lib/lucky_luciano.rb +5 -0
  94. data/vendor/js-test-core/vendor/lucky-luciano/lib/lucky_luciano/resource.rb +142 -0
  95. data/vendor/js-test-core/vendor/lucky-luciano/lib/lucky_luciano/resource/path.rb +24 -0
  96. data/vendor/js-test-core/vendor/lucky-luciano/lib/lucky_luciano/rspec.rb +4 -0
  97. data/vendor/js-test-core/vendor/lucky-luciano/lib/lucky_luciano/rspec/be_http.rb +32 -0
  98. data/vendor/js-test-core/vendor/lucky-luciano/spec/lucky_luciano/resource_spec.rb +276 -0
  99. data/vendor/js-test-core/vendor/lucky-luciano/spec/spec_helper.rb +48 -0
  100. data/vendor/js-test-core/vendor/lucky-luciano/spec/spec_suite.rb +4 -0
  101. data/vendor/js-test-core/vendor/lucky-luciano/syntax_ideas.txt +34 -0
  102. metadata +145 -130
  103. data/core/TODO +0 -2
  104. data/core/lib/jquery-1.2.3.js +0 -3408
  105. data/core/lib/screw.assets.js +0 -36
  106. data/core/lib/screw.server.js +0 -21
  107. data/lib/screw_unit/resources.rb +0 -2
  108. data/lib/screw_unit/resources/spec.rb +0 -37
  109. data/spec/unit/js_test_core/specs/spec_dir_spec.rb +0 -43
  110. data/spec/unit/js_test_core/specs/spec_file_spec.rb +0 -43
  111. data/spec/unit/unit_spec_helper.rb +0 -120
  112. data/spec/unit_suite.rb +0 -10
  113. data/vendor/js-test-core/lib/js_test_core/rack.rb +0 -2
  114. data/vendor/js-test-core/lib/js_test_core/rack/commonlogger.rb +0 -5
  115. data/vendor/js-test-core/lib/js_test_core/rails_server.rb +0 -22
  116. data/vendor/js-test-core/lib/js_test_core/resources/dir.rb +0 -52
  117. data/vendor/js-test-core/lib/js_test_core/resources/file_not_found.rb +0 -15
  118. data/vendor/js-test-core/lib/js_test_core/resources/runners.rb +0 -15
  119. data/vendor/js-test-core/lib/js_test_core/resources/runners/firefox_runner.rb +0 -75
  120. data/vendor/js-test-core/lib/js_test_core/resources/specs/spec_dir.rb +0 -50
  121. data/vendor/js-test-core/lib/js_test_core/resources/specs/spec_file.rb +0 -17
  122. data/vendor/js-test-core/lib/js_test_core/resources/suite.rb +0 -24
  123. data/vendor/js-test-core/lib/js_test_core/resources/suite_finish.rb +0 -19
  124. data/vendor/js-test-core/lib/js_test_core/selenium.rb +0 -2
  125. data/vendor/js-test-core/lib/js_test_core/selenium/selenium_driver.rb +0 -5
  126. data/vendor/js-test-core/lib/js_test_core/thin.rb +0 -3
  127. data/vendor/js-test-core/lib/js_test_core/thin/backends/js_test_core_server.rb +0 -9
  128. data/vendor/js-test-core/lib/js_test_core/thin/js_test_core_connection.rb +0 -42
  129. data/vendor/js-test-core/spec/example_specs/failing_spec.js +0 -5
  130. data/vendor/js-test-core/spec/example_specs/foo/failing_spec.js +0 -6
  131. data/vendor/js-test-core/spec/example_specs/foo/passing_spec.js +0 -6
  132. data/vendor/js-test-core/spec/unit/js_test_core/rails_server_spec.rb +0 -45
  133. data/vendor/js-test-core/spec/unit/js_test_core/resources/dir_spec.rb +0 -42
  134. data/vendor/js-test-core/spec/unit/js_test_core/resources/file_not_found_spec.rb +0 -26
  135. data/vendor/js-test-core/spec/unit/js_test_core/resources/runner_spec.rb +0 -24
  136. data/vendor/js-test-core/spec/unit/js_test_core/resources/runners/firefox_runner_spec.rb +0 -197
  137. data/vendor/js-test-core/spec/unit/js_test_core/resources/specs/spec_dir_spec.rb +0 -79
  138. data/vendor/js-test-core/spec/unit/js_test_core/resources/specs/spec_file_spec.rb +0 -42
  139. data/vendor/js-test-core/spec/unit/js_test_core/resources/suite_finish_spec.rb +0 -94
  140. data/vendor/js-test-core/spec/unit/js_test_core/resources/suite_spec.rb +0 -44
  141. data/vendor/js-test-core/spec/unit/thin/js_test_core_connection_spec.rb +0 -92
@@ -0,0 +1,28 @@
1
+ module JsTestCore
2
+ module Resources
3
+ class NotFound < Resource
4
+ map "*"
5
+
6
+ get "/" do
7
+ call
8
+ end
9
+
10
+ put "/" do
11
+ call
12
+ end
13
+
14
+ post "/" do
15
+ call
16
+ end
17
+
18
+ delete "/" do
19
+ call
20
+ end
21
+
22
+ def call
23
+ body = Representations::NotFound.new(:message => "File #{request.path_info} not found").to_s
24
+ [ 404, { "Content-Type" => "text/html" }, body ]
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,16 @@
1
+ module JsTestCore
2
+ module Resources
3
+ class Resource < LuckyLuciano::Resource
4
+ protected
5
+
6
+ def spec_path; server.spec_path; end
7
+ def root_path; server.root_path; end
8
+ def framework_path; server.framework_path; end
9
+ def root_url; server.root_url; end
10
+
11
+ def server
12
+ JsTestCore::Configuration
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,51 @@
1
+ module JsTestCore
2
+ module Resources
3
+ class SpecFile < ::JsTestCore::Resources::File
4
+ map "/specs"
5
+
6
+ get "/?" do
7
+ do_get
8
+ end
9
+
10
+ get "*" do
11
+ do_get
12
+ end
13
+
14
+ protected
15
+
16
+ def do_get
17
+ if ::File.exists?(absolute_path)
18
+ if ::File.directory?(absolute_path)
19
+ spec_files = ::Dir["#{absolute_path}/**/*_spec.js"].map do |file|
20
+ ["#{relative_path}#{file.gsub(absolute_path, "")}"]
21
+ end
22
+ get_generated_spec(absolute_path, spec_files)
23
+ else
24
+ super
25
+ end
26
+ elsif ::File.exists?("#{absolute_path}.js")
27
+ get_generated_spec("#{absolute_path}.js", ["#{relative_path}.js"])
28
+ else
29
+ pass
30
+ end
31
+ end
32
+
33
+ def get_generated_spec(real_path, spec_files)
34
+ html = render_spec(spec_files)
35
+ headers = {
36
+ 'Content-Type' => "text/html",
37
+ 'Last-Modified' => ::File.mtime(real_path).rfc822
38
+ }
39
+ [200, headers, html]
40
+ end
41
+
42
+ def render_spec(spec_files)
43
+ JsTestCore.suite_representation_class.new(:spec_files => spec_files).to_s
44
+ end
45
+
46
+ def absolute_path
47
+ @absolute_path ||= ::File.expand_path("#{spec_path}#{relative_path.gsub(%r{^/specs}, "")}")
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,61 +1,14 @@
1
1
  module JsTestCore
2
2
  module Resources
3
- class WebRoot
4
- LOCATIONS = [
5
- ['', lambda do |web_root|
6
- web_root
7
- end],
8
- ['core', lambda do
9
- Resources::Dir.new(JsTestCore::Server.core_path, "/core")
10
- end],
11
- ['implementations', lambda do
12
- Resources::Dir.new(JsTestCore::Server.implementation_root_path, "/implementations")
13
- end],
14
- ['suites', lambda do
15
- Resources::Suite
16
- end],
17
- ['runners', lambda do
18
- Resources::Runners.new
19
- end]
20
- ]
21
-
22
- class << self
23
- attr_accessor :dispatch_strategy
24
- def dispatch_specs
25
- self.dispatch_strategy = :specs
26
- end
27
- end
28
-
29
- attr_reader :public_path
30
- def initialize(public_path)
31
- @public_path = ::File.expand_path(public_path)
32
- end
33
-
34
- def locate(name)
35
- if self.class.dispatch_strategy == :specs && name == 'specs'
36
- return JsTestCore::Resources::Specs::SpecDir.new(JsTestCore::Server.spec_root_path, "/specs")
37
- end
38
-
39
- location, initializer = LOCATIONS.find do |location|
40
- location.first == name
41
- end
42
- if initializer
43
- initializer.call(self)
44
- else
45
- potential_file_in_public_path = "#{public_path}/#{name}"
46
- if ::File.directory?(potential_file_in_public_path)
47
- Resources::Dir.new(potential_file_in_public_path, "/#{name}")
48
- elsif ::File.exists?(potential_file_in_public_path)
49
- Resources::File.new(potential_file_in_public_path, "/#{name}")
50
- else
51
- Resources::FileNotFound.new(name)
52
- end
53
- end
3
+ class WebRoot < Resource
4
+ map "/"
5
+
6
+ get("") do
7
+ "<html><head></head><body>Welcome to the Js Test Server. Click the following link to run you <a href=/specs>spec suite</a>.</body></html>"
54
8
  end
55
9
 
56
- def get(request, response)
57
- response.status = 301
58
- response['Location'] = "/#{self.class.dispatch_strategy}"
10
+ get("js_test_server.js") do
11
+ File.render_file(Configuration.js_test_core_js_path)
59
12
  end
60
13
  end
61
14
  end
@@ -1,111 +1,84 @@
1
1
  module JsTestCore
2
2
  class Server
3
3
  class << self
4
- attr_accessor :instance
5
-
6
- def run(spec_root_path, implementation_root_path, public_path, server_options = {})
7
- server_options[:Host] ||= DEFAULT_HOST
8
- server_options[:Port] ||= DEFAULT_PORT
9
- @instance = new(spec_root_path, implementation_root_path, public_path, server_options[:Host], server_options[:Port])
10
- instance.run server_options
4
+ attr_writer :instance
5
+ def instance
6
+ @instance ||= new
11
7
  end
12
-
13
- def spec_root_path; instance.spec_root_path; end
14
- def implementation_root_path; instance.implementation_root_path; end
15
- def public_path; instance.public_path; end
16
- def core_path; instance.core_path; end
17
- def test_dir_class; instance.test_dir_class; end
18
- def test_file_class; instance.test_file_class; end
19
- def connection; instance.connection; end
20
- def request; instance.request; end
21
- def response; instance.response; end
22
- def root_url; instance.root_url; end
23
- end
24
-
25
- attr_reader :host, :port, :spec_root_path, :implementation_root_path, :public_path
26
-
27
- def initialize(spec_root_path, implementation_root_path, public_path, host=DEFAULT_HOST, port=DEFAULT_PORT)
28
- dir = ::File.dirname(__FILE__)
29
- @spec_root_path = ::File.expand_path(spec_root_path)
30
- @implementation_root_path = ::File.expand_path(implementation_root_path)
31
- @public_path = ::File.expand_path(public_path)
32
- @host = host
33
- @port = port
34
- end
35
-
36
- def run(options)
37
- server = ::Thin::Server.new(options[:Host], options[:Port], self)
38
- server.backend = ::Thin::Backends::JsTestCoreServer.new(options[:Host], options[:Port])
39
- server.backend.server = server
40
- server.start!
41
- end
42
-
43
- def call(env)
44
- self.connection = env['js_test_core.connection']
45
- self.request = Rack::Request.new(env)
46
- self.response = Rack::Response.new
47
- method = request.request_method.downcase.to_sym
48
- get_resource(request).send(method, request, response)
49
- response.finish
50
- ensure
51
- self.connection = nil
52
- self.request = nil
53
- self.response = nil
54
8
  end
55
9
 
56
- def connection
57
- Thread.current[:connection]
58
- end
59
-
60
- def request
61
- Thread.current[:request]
62
- end
10
+ DEFAULTS = {
11
+ :host => "0.0.0.0",
12
+ :port => 8080,
13
+ :spec_path => File.expand_path("./spec/javascripts"),
14
+ :root_path => File.expand_path("./public"),
15
+ }
16
+
17
+ def cli(*argv)
18
+ opts = Trollop.options(argv) do
19
+ opt(
20
+ :framework_name,
21
+ "The name of the test framework you want to use. e.g. --framework-name=jasmine",
22
+ :type => String,
23
+ :default => DEFAULTS[:framework_name]
24
+ )
25
+ opt(
26
+ :framework_path,
27
+ "The name of the test framework you want to use. e.g. --framework-path=./specs/jasmine_core",
28
+ :type => String,
29
+ :default => DEFAULTS[:framework_path]
30
+ )
31
+ opt(
32
+ :spec_path,
33
+ "The path to the spec files. e.g. --spec-path=./specs",
34
+ :type => String,
35
+ :default => DEFAULTS[:spec_path]
36
+ )
37
+ opt(
38
+ :root_path,
39
+ "The root path of the server. e.g. --root-path=./public",
40
+ :type => String,
41
+ :default => DEFAULTS[:root_path]
42
+ )
43
+ opt(
44
+ :port,
45
+ "The server port",
46
+ :type => Integer,
47
+ :default => DEFAULTS[:port]
48
+ )
49
+ end
63
50
 
64
- def response
65
- Thread.current[:response]
51
+ JsTestCore.port = opts[:port]
52
+ JsTestCore.framework_name = opts[:framework_name]
53
+ JsTestCore.framework_path = opts[:framework_path]
54
+ JsTestCore.spec_path = opts[:spec_path]
55
+ JsTestCore.root_path = opts[:root_path]
56
+ STDOUT.puts "root-path is #{JsTestCore.root_path}"
57
+ STDOUT.puts "spec-path is #{JsTestCore.spec_path}"
58
+ start
66
59
  end
67
60
 
68
- def root_url
69
- "http://#{host}:#{port}"
61
+ def start
62
+ require "thin"
63
+ Thin::Runner.new([
64
+ "--port", JsTestCore.port.to_s,
65
+ "--rackup", File.expand_path(rackup_path),
66
+ "start"]
67
+ ).run!
70
68
  end
71
69
 
72
- def core_path
73
- JsTestCore.core_path
74
- end
70
+ def standalone_rackup(rack_builder)
71
+ require "sinatra"
75
72
 
76
- def test_dir_class
77
- JsTestCore.adapter.test_dir_class
73
+ rack_builder.use JsTestCore::App
74
+ rack_builder.run Sinatra::Application
78
75
  end
79
76
 
80
- def test_file_class
81
- JsTestCore.adapter.test_file_class
82
- end
83
-
84
77
  protected
85
- def connection=(connection)
86
- Thread.current[:connection] = connection
87
- end
88
-
89
- def request=(request)
90
- Thread.current[:request] = request
91
- end
92
78
 
93
- def response=(response)
94
- Thread.current[:response] = response
95
- end
96
-
97
- def path_parts(req)
98
- request.path_info.split('/').reject { |part| part == "" }
99
- end
100
-
101
- def get_resource(request)
102
- path_parts(request).inject(Resources::WebRoot.new(public_path)) do |resource, child_resource_name|
103
- resource.locate(child_resource_name)
104
- end
105
- rescue Exception => e
106
- detailed_exception = Exception.new("Error handling path #{request.path_info}\n#{e.message}")
107
- detailed_exception.set_backtrace(e.backtrace)
108
- raise detailed_exception
79
+ def rackup_path
80
+ dir = File.dirname(__FILE__)
81
+ File.expand_path("#{dir}/../../standalone.ru")
109
82
  end
110
83
  end
111
84
  end
@@ -0,0 +1,541 @@
1
+ (function() {
2
+ function JsTestServer() {
3
+ };
4
+ window.JsTestServer = JsTestServer;
5
+
6
+ JsTestServer.status = function() {
7
+ throw "You must implement the JsTestServer.status method";
8
+ };
9
+
10
+ JsTestServer.Assets = {};
11
+ JsTestServer.Assets.use_cache_buster = false; // TODO: NS/CTI - make this configurable from the UI.
12
+ var required_paths = [];
13
+ var included_stylesheets = {};
14
+ var cache_buster = parseInt(new Date().getTime()/(1*1000));
15
+
16
+ function tag(name, attributes) {
17
+ var html = "<" + name;
18
+ for(var attribute in attributes) {
19
+ html += (" " + attribute + "='" + attributes[attribute]) + "'";
20
+ };
21
+ html += "></";
22
+ html += name;
23
+ html += ">";
24
+ return html;
25
+ }
26
+
27
+ JsTestServer.Assets.require = function(javascript_path, onload) {
28
+ if(!required_paths[javascript_path]) {
29
+ var full_path = javascript_path + ".js";
30
+ if (JsTestServer.Assets.use_cache_buster) {
31
+ full_path += '?' + cache_buster;
32
+ }
33
+ document.write(tag("script", {src: full_path, type: 'text/javascript'}));
34
+ if(onload) {
35
+ var scripts = document.getElementsByTagName('script');
36
+ scripts[scripts.length-1].onload = onload;
37
+ }
38
+ required_paths[javascript_path] = true;
39
+ }
40
+ };
41
+
42
+ JsTestServer.Assets.stylesheet = function(stylesheet_path) {
43
+ if(!included_stylesheets[stylesheet_path]) {
44
+ var full_path = stylesheet_path + ".css";
45
+ if(JsTestServer.Assets.use_cache_buster) {
46
+ full_path += '?' + cache_buster;
47
+ }
48
+ document.write(tag("link", {rel: 'stylesheet', type: 'text/css', href: full_path}));
49
+ included_stylesheets[stylesheet_path] = true;
50
+ }
51
+ };
52
+
53
+ window.require = JsTestServer.Assets.require;
54
+ window.stylesheet = JsTestServer.Assets.stylesheet;
55
+ })();
56
+
57
+
58
+ //////////////////////////////////////////////////////////////////
59
+ // Inlining json2.js library because there should only be one js script tag
60
+ // and its simpler to inline rather than cat the js together on the server.
61
+ //////////////////////////////////////////////////////////////////
62
+
63
+ /*
64
+ http://www.JSON.org/json2.js
65
+ 2009-06-29
66
+
67
+ Public Domain.
68
+
69
+ NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
70
+
71
+ See http://www.JSON.org/js.html
72
+
73
+ This file creates a global JSON object containing two methods: stringify
74
+ and parse.
75
+
76
+ JSON.stringify(value, replacer, space)
77
+ value any JavaScript value, usually an object or array.
78
+
79
+ replacer an optional parameter that determines how object
80
+ values are stringified for objects. It can be a
81
+ function or an array of strings.
82
+
83
+ space an optional parameter that specifies the indentation
84
+ of nested structures. If it is omitted, the text will
85
+ be packed without extra whitespace. If it is a number,
86
+ it will specify the number of spaces to indent at each
87
+ level. If it is a string (such as '\t' or '&nbsp;'),
88
+ it contains the characters used to indent at each level.
89
+
90
+ This method produces a JSON text from a JavaScript value.
91
+
92
+ When an object value is found, if the object contains a toJSON
93
+ method, its toJSON method will be called and the result will be
94
+ stringified. A toJSON method does not serialize: it returns the
95
+ value represented by the name/value pair that should be serialized,
96
+ or undefined if nothing should be serialized. The toJSON method
97
+ will be passed the key associated with the value, and this will be
98
+ bound to the object holding the key.
99
+
100
+ For example, this would serialize Dates as ISO strings.
101
+
102
+ Date.prototype.toJSON = function (key) {
103
+ function f(n) {
104
+ // Format integers to have at least two digits.
105
+ return n < 10 ? '0' + n : n;
106
+ }
107
+
108
+ return this.getUTCFullYear() + '-' +
109
+ f(this.getUTCMonth() + 1) + '-' +
110
+ f(this.getUTCDate()) + 'T' +
111
+ f(this.getUTCHours()) + ':' +
112
+ f(this.getUTCMinutes()) + ':' +
113
+ f(this.getUTCSeconds()) + 'Z';
114
+ };
115
+
116
+ You can provide an optional replacer method. It will be passed the
117
+ key and value of each member, with this bound to the containing
118
+ object. The value that is returned from your method will be
119
+ serialized. If your method returns undefined, then the member will
120
+ be excluded from the serialization.
121
+
122
+ If the replacer parameter is an array of strings, then it will be
123
+ used to select the members to be serialized. It filters the results
124
+ such that only members with keys listed in the replacer array are
125
+ stringified.
126
+
127
+ Values that do not have JSON representations, such as undefined or
128
+ functions, will not be serialized. Such values in objects will be
129
+ dropped; in arrays they will be replaced with null. You can use
130
+ a replacer function to replace those with JSON values.
131
+ JSON.stringify(undefined) returns undefined.
132
+
133
+ The optional space parameter produces a stringification of the
134
+ value that is filled with line breaks and indentation to make it
135
+ easier to read.
136
+
137
+ If the space parameter is a non-empty string, then that string will
138
+ be used for indentation. If the space parameter is a number, then
139
+ the indentation will be that many spaces.
140
+
141
+ Example:
142
+
143
+ text = JSON.stringify(['e', {pluribus: 'unum'}]);
144
+ // text is '["e",{"pluribus":"unum"}]'
145
+
146
+
147
+ text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
148
+ // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
149
+
150
+ text = JSON.stringify([new Date()], function (key, value) {
151
+ return this[key] instanceof Date ?
152
+ 'Date(' + this[key] + ')' : value;
153
+ });
154
+ // text is '["Date(---current time---)"]'
155
+
156
+
157
+ JSON.parse(text, reviver)
158
+ This method parses a JSON text to produce an object or array.
159
+ It can throw a SyntaxError exception.
160
+
161
+ The optional reviver parameter is a function that can filter and
162
+ transform the results. It receives each of the keys and values,
163
+ and its return value is used instead of the original value.
164
+ If it returns what it received, then the structure is not modified.
165
+ If it returns undefined then the member is deleted.
166
+
167
+ Example:
168
+
169
+ // Parse the text. Values that look like ISO date strings will
170
+ // be converted to Date objects.
171
+
172
+ myData = JSON.parse(text, function (key, value) {
173
+ var a;
174
+ if (typeof value === 'string') {
175
+ a =
176
+ /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
177
+ if (a) {
178
+ return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
179
+ +a[5], +a[6]));
180
+ }
181
+ }
182
+ return value;
183
+ });
184
+
185
+ myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
186
+ var d;
187
+ if (typeof value === 'string' &&
188
+ value.slice(0, 5) === 'Date(' &&
189
+ value.slice(-1) === ')') {
190
+ d = new Date(value.slice(5, -1));
191
+ if (d) {
192
+ return d;
193
+ }
194
+ }
195
+ return value;
196
+ });
197
+
198
+
199
+ This is a reference implementation. You are free to copy, modify, or
200
+ redistribute.
201
+
202
+ This code should be minified before deployment.
203
+ See http://javascript.crockford.com/jsmin.html
204
+
205
+ USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
206
+ NOT CONTROL.
207
+ */
208
+
209
+ /*jslint evil: true */
210
+
211
+ /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
212
+ call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
213
+ getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
214
+ lastIndex, length, parse, prototype, push, replace, slice, stringify,
215
+ test, toJSON, toString, valueOf
216
+ */
217
+
218
+ // Create a JSON object only if one does not already exist. We create the
219
+ // methods in a closure to avoid creating global variables.
220
+
221
+ (function(JsTestServer) {
222
+ var JSON = JSON || {};
223
+ JsTestServer.JSON = JSON;
224
+
225
+ (function () {
226
+
227
+ function f(n) {
228
+ // Format integers to have at least two digits.
229
+ return n < 10 ? '0' + n : n;
230
+ }
231
+
232
+ if (typeof Date.prototype.toJSON !== 'function') {
233
+
234
+ Date.prototype.toJSON = function (key) {
235
+
236
+ return isFinite(this.valueOf()) ?
237
+ this.getUTCFullYear() + '-' +
238
+ f(this.getUTCMonth() + 1) + '-' +
239
+ f(this.getUTCDate()) + 'T' +
240
+ f(this.getUTCHours()) + ':' +
241
+ f(this.getUTCMinutes()) + ':' +
242
+ f(this.getUTCSeconds()) + 'Z' : null;
243
+ };
244
+
245
+ String.prototype.toJSON =
246
+ Number.prototype.toJSON =
247
+ Boolean.prototype.toJSON = function (key) {
248
+ return this.valueOf();
249
+ };
250
+ }
251
+
252
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
253
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
254
+ gap,
255
+ indent,
256
+ meta = { // table of character substitutions
257
+ '\b': '\\b',
258
+ '\t': '\\t',
259
+ '\n': '\\n',
260
+ '\f': '\\f',
261
+ '\r': '\\r',
262
+ '"' : '\\"',
263
+ '\\': '\\\\'
264
+ },
265
+ rep;
266
+
267
+
268
+ function quote(string) {
269
+
270
+ // If the string contains no control characters, no quote characters, and no
271
+ // backslash characters, then we can safely slap some quotes around it.
272
+ // Otherwise we must also replace the offending characters with safe escape
273
+ // sequences.
274
+
275
+ escapable.lastIndex = 0;
276
+ return escapable.test(string) ?
277
+ '"' + string.replace(escapable, function (a) {
278
+ var c = meta[a];
279
+ return typeof c === 'string' ? c :
280
+ '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
281
+ }) + '"' :
282
+ '"' + string + '"';
283
+ }
284
+
285
+
286
+ function str(key, holder) {
287
+
288
+ // Produce a string from holder[key].
289
+
290
+ var i, // The loop counter.
291
+ k, // The member key.
292
+ v, // The member value.
293
+ length,
294
+ mind = gap,
295
+ partial,
296
+ value = holder[key];
297
+
298
+ // If the value has a toJSON method, call it to obtain a replacement value.
299
+
300
+ if (value && typeof value === 'object' &&
301
+ typeof value.toJSON === 'function') {
302
+ value = value.toJSON(key);
303
+ }
304
+
305
+ // If we were called with a replacer function, then call the replacer to
306
+ // obtain a replacement value.
307
+
308
+ if (typeof rep === 'function') {
309
+ value = rep.call(holder, key, value);
310
+ }
311
+
312
+ // What happens next depends on the value's type.
313
+
314
+ switch (typeof value) {
315
+ case 'string':
316
+ return quote(value);
317
+
318
+ case 'number':
319
+
320
+ // JSON numbers must be finite. Encode non-finite numbers as null.
321
+
322
+ return isFinite(value) ? String(value) : 'null';
323
+
324
+ case 'boolean':
325
+ case 'null':
326
+
327
+ // If the value is a boolean or null, convert it to a string. Note:
328
+ // typeof null does not produce 'null'. The case is included here in
329
+ // the remote chance that this gets fixed someday.
330
+
331
+ return String(value);
332
+
333
+ // If the type is 'object', we might be dealing with an object or an array or
334
+ // null.
335
+
336
+ case 'object':
337
+
338
+ // Due to a specification blunder in ECMAScript, typeof null is 'object',
339
+ // so watch out for that case.
340
+
341
+ if (!value) {
342
+ return 'null';
343
+ }
344
+
345
+ // Make an array to hold the partial results of stringifying this object value.
346
+
347
+ gap += indent;
348
+ partial = [];
349
+
350
+ // Is the value an array?
351
+
352
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
353
+
354
+ // The value is an array. Stringify every element. Use null as a placeholder
355
+ // for non-JSON values.
356
+
357
+ length = value.length;
358
+ for (i = 0; i < length; i += 1) {
359
+ partial[i] = str(i, value) || 'null';
360
+ }
361
+
362
+ // Join all of the elements together, separated with commas, and wrap them in
363
+ // brackets.
364
+
365
+ v = partial.length === 0 ? '[]' :
366
+ gap ? '[\n' + gap +
367
+ partial.join(',\n' + gap) + '\n' +
368
+ mind + ']' :
369
+ '[' + partial.join(',') + ']';
370
+ gap = mind;
371
+ return v;
372
+ }
373
+
374
+ // If the replacer is an array, use it to select the members to be stringified.
375
+
376
+ if (rep && typeof rep === 'object') {
377
+ length = rep.length;
378
+ for (i = 0; i < length; i += 1) {
379
+ k = rep[i];
380
+ if (typeof k === 'string') {
381
+ v = str(k, value);
382
+ if (v) {
383
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
384
+ }
385
+ }
386
+ }
387
+ } else {
388
+
389
+ // Otherwise, iterate through all of the keys in the object.
390
+
391
+ for (k in value) {
392
+ if (Object.hasOwnProperty.call(value, k)) {
393
+ v = str(k, value);
394
+ if (v) {
395
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
396
+ }
397
+ }
398
+ }
399
+ }
400
+
401
+ // Join all of the member texts together, separated with commas,
402
+ // and wrap them in braces.
403
+
404
+ v = partial.length === 0 ? '{}' :
405
+ gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
406
+ mind + '}' : '{' + partial.join(',') + '}';
407
+ gap = mind;
408
+ return v;
409
+ }
410
+ }
411
+
412
+ // If the JSON object does not yet have a stringify method, give it one.
413
+
414
+ if (typeof JSON.stringify !== 'function') {
415
+ JSON.stringify = function (value, replacer, space) {
416
+
417
+ // The stringify method takes a value and an optional replacer, and an optional
418
+ // space parameter, and returns a JSON text. The replacer can be a function
419
+ // that can replace values, or an array of strings that will select the keys.
420
+ // A default replacer method can be provided. Use of the space parameter can
421
+ // produce text that is more easily readable.
422
+
423
+ var i;
424
+ gap = '';
425
+ indent = '';
426
+
427
+ // If the space parameter is a number, make an indent string containing that
428
+ // many spaces.
429
+
430
+ if (typeof space === 'number') {
431
+ for (i = 0; i < space; i += 1) {
432
+ indent += ' ';
433
+ }
434
+
435
+ // If the space parameter is a string, it will be used as the indent string.
436
+
437
+ } else if (typeof space === 'string') {
438
+ indent = space;
439
+ }
440
+
441
+ // If there is a replacer, it must be a function or an array.
442
+ // Otherwise, throw an error.
443
+
444
+ rep = replacer;
445
+ if (replacer && typeof replacer !== 'function' &&
446
+ (typeof replacer !== 'object' ||
447
+ typeof replacer.length !== 'number')) {
448
+ throw new Error('JSON.stringify');
449
+ }
450
+
451
+ // Make a fake root object containing our value under the key of ''.
452
+ // Return the result of stringifying the value.
453
+
454
+ return str('', {'': value});
455
+ };
456
+ }
457
+
458
+
459
+ // If the JSON object does not yet have a parse method, give it one.
460
+
461
+ if (typeof JSON.parse !== 'function') {
462
+ JSON.parse = function (text, reviver) {
463
+
464
+ // The parse method takes a text and an optional reviver function, and returns
465
+ // a JavaScript value if the text is a valid JSON text.
466
+
467
+ var j;
468
+
469
+ function walk(holder, key) {
470
+
471
+ // The walk method is used to recursively walk the resulting structure so
472
+ // that modifications can be made.
473
+
474
+ var k, v, value = holder[key];
475
+ if (value && typeof value === 'object') {
476
+ for (k in value) {
477
+ if (Object.hasOwnProperty.call(value, k)) {
478
+ v = walk(value, k);
479
+ if (v !== undefined) {
480
+ value[k] = v;
481
+ } else {
482
+ delete value[k];
483
+ }
484
+ }
485
+ }
486
+ }
487
+ return reviver.call(holder, key, value);
488
+ }
489
+
490
+
491
+ // Parsing happens in four stages. In the first stage, we replace certain
492
+ // Unicode characters with escape sequences. JavaScript handles many characters
493
+ // incorrectly, either silently deleting them, or treating them as line endings.
494
+
495
+ cx.lastIndex = 0;
496
+ if (cx.test(text)) {
497
+ text = text.replace(cx, function (a) {
498
+ return '\\u' +
499
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
500
+ });
501
+ }
502
+
503
+ // In the second stage, we run the text against regular expressions that look
504
+ // for non-JSON patterns. We are especially concerned with '()' and 'new'
505
+ // because they can cause invocation, and '=' because it can cause mutation.
506
+ // But just to be safe, we want to reject all unexpected forms.
507
+
508
+ // We split the second stage into 4 regexp operations in order to work around
509
+ // crippling inefficiencies in IE's and Safari's regexp engines. First we
510
+ // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
511
+ // replace all simple value tokens with ']' characters. Third, we delete all
512
+ // open brackets that follow a colon or comma or that begin the text. Finally,
513
+ // we look to see that the remaining characters are only whitespace or ']' or
514
+ // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
515
+
516
+ if (/^[\],:{}\s]*$/.
517
+ test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
518
+ replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
519
+ replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
520
+
521
+ // In the third stage we use the eval function to compile the text into a
522
+ // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
523
+ // in JavaScript: it can begin a block or an object literal. We wrap the text
524
+ // in parens to eliminate the ambiguity.
525
+
526
+ j = eval('(' + text + ')');
527
+
528
+ // In the optional fourth stage, we recursively walk the new structure, passing
529
+ // each name/value pair to a reviver function for possible transformation.
530
+
531
+ return typeof reviver === 'function' ?
532
+ walk({'': j}, '') : j;
533
+ }
534
+
535
+ // If the text is not JSON parseable, then a SyntaxError is thrown.
536
+
537
+ throw new SyntaxError('JSON.parse');
538
+ };
539
+ }
540
+ }());
541
+ })(JsTestServer);