jbarnette-johnson 1.0.0.200806240111

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 (137) hide show
  1. data/CHANGELOG +5 -0
  2. data/MANIFEST +385 -0
  3. data/MINGW32.mk +124 -0
  4. data/README.rdoc +51 -0
  5. data/Rakefile +166 -0
  6. data/bin/johnson +107 -0
  7. data/cross-compile.txt +38 -0
  8. data/ext/spidermonkey/context.c +122 -0
  9. data/ext/spidermonkey/context.h +19 -0
  10. data/ext/spidermonkey/conversions.c +286 -0
  11. data/ext/spidermonkey/conversions.h +18 -0
  12. data/ext/spidermonkey/debugger.c +208 -0
  13. data/ext/spidermonkey/debugger.h +9 -0
  14. data/ext/spidermonkey/extconf.rb +25 -0
  15. data/ext/spidermonkey/extensions.c +37 -0
  16. data/ext/spidermonkey/extensions.h +12 -0
  17. data/ext/spidermonkey/global.c +40 -0
  18. data/ext/spidermonkey/global.h +11 -0
  19. data/ext/spidermonkey/idhash.c +16 -0
  20. data/ext/spidermonkey/idhash.h +8 -0
  21. data/ext/spidermonkey/immutable_node.c.erb +522 -0
  22. data/ext/spidermonkey/immutable_node.h +22 -0
  23. data/ext/spidermonkey/jroot.h +187 -0
  24. data/ext/spidermonkey/js_land_proxy.c +609 -0
  25. data/ext/spidermonkey/js_land_proxy.h +20 -0
  26. data/ext/spidermonkey/ruby_land_proxy.c +537 -0
  27. data/ext/spidermonkey/ruby_land_proxy.h +17 -0
  28. data/ext/spidermonkey/runtime.c +304 -0
  29. data/ext/spidermonkey/runtime.h +25 -0
  30. data/ext/spidermonkey/spidermonkey.c +20 -0
  31. data/ext/spidermonkey/spidermonkey.h +29 -0
  32. data/js/johnson/browser.js +9 -0
  33. data/js/johnson/browser/env.js +687 -0
  34. data/js/johnson/browser/jquery.js +3444 -0
  35. data/js/johnson/browser/xmlsax.js +1564 -0
  36. data/js/johnson/browser/xmlw3cdom.js +4189 -0
  37. data/js/johnson/cli.js +30 -0
  38. data/js/johnson/prelude.js +80 -0
  39. data/js/johnson/template.js +29 -0
  40. data/lib/hoe.rb +748 -0
  41. data/lib/johnson.rb +46 -0
  42. data/lib/johnson/cli.rb +7 -0
  43. data/lib/johnson/cli/options.rb +56 -0
  44. data/lib/johnson/error.rb +4 -0
  45. data/lib/johnson/nodes.rb +7 -0
  46. data/lib/johnson/nodes/binary_node.rb +64 -0
  47. data/lib/johnson/nodes/for.rb +14 -0
  48. data/lib/johnson/nodes/for_in.rb +12 -0
  49. data/lib/johnson/nodes/function.rb +13 -0
  50. data/lib/johnson/nodes/list.rb +27 -0
  51. data/lib/johnson/nodes/node.rb +68 -0
  52. data/lib/johnson/nodes/ternary_node.rb +20 -0
  53. data/lib/johnson/parser.rb +21 -0
  54. data/lib/johnson/parser/syntax_error.rb +13 -0
  55. data/lib/johnson/runtime.rb +55 -0
  56. data/lib/johnson/spidermonkey/context.rb +10 -0
  57. data/lib/johnson/spidermonkey/debugger.rb +67 -0
  58. data/lib/johnson/spidermonkey/immutable_node.rb +280 -0
  59. data/lib/johnson/spidermonkey/js_land_proxy.rb +62 -0
  60. data/lib/johnson/spidermonkey/mutable_tree_visitor.rb +233 -0
  61. data/lib/johnson/spidermonkey/ruby_land_proxy.rb +52 -0
  62. data/lib/johnson/spidermonkey/runtime.rb +94 -0
  63. data/lib/johnson/version.rb +4 -0
  64. data/lib/johnson/visitable.rb +16 -0
  65. data/lib/johnson/visitors.rb +4 -0
  66. data/lib/johnson/visitors/dot_visitor.rb +167 -0
  67. data/lib/johnson/visitors/ecma_visitor.rb +315 -0
  68. data/lib/johnson/visitors/enumerating_visitor.rb +115 -0
  69. data/lib/johnson/visitors/sexp_visitor.rb +172 -0
  70. data/lib/rails/init.rb +37 -0
  71. data/test/assets/index.html +38 -0
  72. data/test/assets/jquery_test.html +186 -0
  73. data/test/helper.rb +58 -0
  74. data/test/johnson/browser_test.rb +38 -0
  75. data/test/johnson/conversions/array_test.rb +32 -0
  76. data/test/johnson/conversions/boolean_test.rb +17 -0
  77. data/test/johnson/conversions/callable_test.rb +34 -0
  78. data/test/johnson/conversions/file_test.rb +15 -0
  79. data/test/johnson/conversions/nil_test.rb +20 -0
  80. data/test/johnson/conversions/number_test.rb +34 -0
  81. data/test/johnson/conversions/regexp_test.rb +24 -0
  82. data/test/johnson/conversions/string_test.rb +26 -0
  83. data/test/johnson/conversions/struct_test.rb +15 -0
  84. data/test/johnson/conversions/symbol_test.rb +19 -0
  85. data/test/johnson/conversions/thread_test.rb +24 -0
  86. data/test/johnson/error_test.rb +9 -0
  87. data/test/johnson/extensions_test.rb +56 -0
  88. data/test/johnson/nodes/array_literal_test.rb +57 -0
  89. data/test/johnson/nodes/array_node_test.rb +26 -0
  90. data/test/johnson/nodes/binary_node_test.rb +61 -0
  91. data/test/johnson/nodes/bracket_access_test.rb +16 -0
  92. data/test/johnson/nodes/delete_test.rb +11 -0
  93. data/test/johnson/nodes/do_while_test.rb +12 -0
  94. data/test/johnson/nodes/dot_accessor_test.rb +15 -0
  95. data/test/johnson/nodes/export_test.rb +9 -0
  96. data/test/johnson/nodes/for_test.rb +54 -0
  97. data/test/johnson/nodes/function_test.rb +71 -0
  98. data/test/johnson/nodes/if_test.rb +41 -0
  99. data/test/johnson/nodes/import_test.rb +13 -0
  100. data/test/johnson/nodes/label_test.rb +19 -0
  101. data/test/johnson/nodes/object_literal_test.rb +110 -0
  102. data/test/johnson/nodes/return_test.rb +16 -0
  103. data/test/johnson/nodes/semi_test.rb +8 -0
  104. data/test/johnson/nodes/switch_test.rb +55 -0
  105. data/test/johnson/nodes/ternary_test.rb +25 -0
  106. data/test/johnson/nodes/throw_test.rb +9 -0
  107. data/test/johnson/nodes/try_node_test.rb +59 -0
  108. data/test/johnson/nodes/typeof_test.rb +11 -0
  109. data/test/johnson/nodes/unary_node_test.rb +23 -0
  110. data/test/johnson/nodes/void_test.rb +11 -0
  111. data/test/johnson/nodes/while_test.rb +26 -0
  112. data/test/johnson/nodes/with_test.rb +10 -0
  113. data/test/johnson/prelude_test.rb +56 -0
  114. data/test/johnson/runtime_test.rb +46 -0
  115. data/test/johnson/spidermonkey/context_test.rb +21 -0
  116. data/test/johnson/spidermonkey/immutable_node_test.rb +34 -0
  117. data/test/johnson/spidermonkey/js_land_proxy_test.rb +236 -0
  118. data/test/johnson/spidermonkey/ruby_land_proxy_test.rb +225 -0
  119. data/test/johnson/spidermonkey/runtime_test.rb +17 -0
  120. data/test/johnson/version_test.rb +13 -0
  121. data/test/johnson/visitors/dot_visitor_test.rb +39 -0
  122. data/test/johnson/visitors/enumerating_visitor_test.rb +12 -0
  123. data/test/johnson_test.rb +16 -0
  124. data/test/jquery_units/test.js +27 -0
  125. data/test/jquery_units/test_helper.js +197 -0
  126. data/test/jquery_units/units/ajax.js +795 -0
  127. data/test/jquery_units/units/core.js +1563 -0
  128. data/test/jquery_units/units/event.js +299 -0
  129. data/test/jquery_units/units/fx.js +427 -0
  130. data/test/jquery_units/units/offset.js +112 -0
  131. data/test/jquery_units/units/selector.js +224 -0
  132. data/test/jspec/helper.js +7 -0
  133. data/test/jspec/jspec.js +192 -0
  134. data/test/jspec/simple_spec.js +68 -0
  135. data/test/parser_test.rb +276 -0
  136. data/todo/.keep +0 -0
  137. metadata +501 -0
@@ -0,0 +1,225 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "/../../helper"))
2
+
3
+ module Johnson
4
+ module SpiderMonkey
5
+ class RubyLandProxyTest < Johnson::TestCase
6
+ def setup
7
+ @runtime = Johnson::Runtime.new(Johnson::SpiderMonkey::Runtime)
8
+ end
9
+
10
+ def test_constructing_a_proxy_directly_asplodes
11
+ assert_raise(Johnson::Error) { Johnson::SpiderMonkey::RubyLandProxy.new }
12
+ end
13
+
14
+ def test_objects_get_wrapped_as_proxies
15
+ assert_kind_of(Johnson::SpiderMonkey::RubyLandProxy, @runtime.evaluate("x = {}"))
16
+ assert_kind_of(Johnson::SpiderMonkey::RubyLandProxy, @runtime.evaluate("new Object()"))
17
+ end
18
+
19
+ def test_proxies_get_unwrapped_when_roundtripping
20
+ proxy = @runtime.evaluate("x = {}")
21
+ @runtime["y"] = proxy
22
+ assert(@runtime.evaluate("x === y"))
23
+ end
24
+
25
+ def test_array_indexable
26
+ proxy = @runtime.evaluate("var x = [1,2,3]; x")
27
+ assert_equal(1, proxy[0])
28
+ assert_equal(1, proxy['0'])
29
+
30
+ proxy[0] = 10
31
+ assert_js_equal(10, 'x[0]')
32
+ end
33
+
34
+ def test_hash_indexable
35
+ proxy = @runtime.evaluate("var x = { 0: 1, 1: 2, 2: 3 }; x")
36
+ assert_equal(1, proxy[0])
37
+ assert_equal(1, proxy['0'])
38
+
39
+ proxy[0] = 10
40
+ assert_js_equal(10, 'x[0]')
41
+ end
42
+
43
+ def test_functions_get_wrapped_as_proxies
44
+ f = @runtime.evaluate("function() {}")
45
+ assert_kind_of(Johnson::SpiderMonkey::RubyLandProxy, f)
46
+ assert(f.function?)
47
+ end
48
+
49
+ def test_function?
50
+ f = @runtime.evaluate("function() {}")
51
+ assert_kind_of(Johnson::SpiderMonkey::RubyLandProxy, f)
52
+ assert(f.function?)
53
+
54
+ f = @runtime.evaluate("new Object()")
55
+ assert_kind_of(Johnson::SpiderMonkey::RubyLandProxy, f)
56
+ assert(!f.function?)
57
+ end
58
+
59
+ def test_calling_non_functions_complains
60
+ assert_raise(RuntimeError) { @runtime.evaluate("new Object()").call }
61
+ end
62
+
63
+ def test_functions_can_be_called
64
+ f = @runtime.evaluate("function() { return 42; }")
65
+ assert_equal(42, f.call)
66
+ end
67
+
68
+ def test_functions_can_be_called_with_args
69
+ f = @runtime.evaluate("function(x) { return x * 2; }")
70
+ assert_equal(84, f.call(42))
71
+ end
72
+
73
+ def test_functions_can_be_used_as_procs
74
+ f = @runtime.evaluate("function(x) { return x * 2; }")
75
+ a = [1, 2, 3]
76
+
77
+ assert_equal([2, 4, 6], a.collect(&f))
78
+ end
79
+
80
+ def test_function_proxies_are_called_with_a_global_this
81
+ f = @runtime.evaluate("x = 42; function() { return this.x; }")
82
+ assert_equal(42, f.call)
83
+ end
84
+
85
+ def test_can_be_indexed_by_string
86
+ proxy = @runtime.evaluate("x = { foo: 42 }")
87
+ assert_kind_of(Johnson::SpiderMonkey::RubyLandProxy, proxy)
88
+
89
+ assert_equal(42, proxy["foo"])
90
+
91
+ proxy["foo"] = 99
92
+ proxy["bar"] = 42
93
+
94
+ assert_js_equal(99, "x.foo")
95
+ assert_equal(99, proxy["foo"])
96
+ assert_equal(42, proxy["bar"])
97
+ end
98
+
99
+ def test_multilevel_indexing_works
100
+ proxy = @runtime.evaluate("x = { foo: { bar: 42 , baz: function() { return 42 } } }")
101
+ assert_equal(42, proxy["foo"]["bar"])
102
+ assert_equal(42, proxy["foo"]["baz"].call)
103
+ end
104
+
105
+ def test_respond_to_works
106
+ proxy = @runtime.evaluate("x = { foo: 42 }")
107
+ assert(!proxy.respond_to?(:bar))
108
+ assert(proxy.respond_to?(:foo))
109
+ end
110
+
111
+ def test_respond_to_always_returns_true_for_assignment
112
+ proxy = @runtime.evaluate("x = {}")
113
+ assert(proxy.respond_to?(:bar=))
114
+ end
115
+
116
+ def test_accessor
117
+ proxy = @runtime.evaluate("x = { foo: 42 }")
118
+ assert_equal(42, proxy.foo)
119
+ end
120
+
121
+ def test_mutator
122
+ proxy = @runtime.evaluate("x = {}")
123
+ proxy.foo = 42
124
+
125
+ assert_js_equal(42, "x.foo")
126
+ assert_equal(42, proxy.foo)
127
+ end
128
+
129
+ def test_method_with_no_arguments
130
+ proxy = @runtime.evaluate("x = { foo: function() { return 42 } }")
131
+ assert_equal(42, proxy.foo)
132
+ end
133
+
134
+ def test_method_with_one_argument
135
+ proxy = @runtime.evaluate("f = { f: function(x) { return x * 2 } }")
136
+ assert_equal(84, proxy.f(42))
137
+ end
138
+
139
+ def test_method_with_multiple_arguments
140
+ proxy = @runtime.evaluate("x = { add: function(x, y) { return x + y } }")
141
+ assert_equal(42, proxy.add(40, 2))
142
+ end
143
+
144
+ def test_supports_each_on_arrays
145
+ proxy = @runtime.evaluate("[1, 2, 3]")
146
+ values = []
147
+
148
+ proxy.each { |n| values << n }
149
+ assert_equal([1, 2, 3], values)
150
+ end
151
+
152
+ def test_supports_each_on_things_that_arent_arrays
153
+ proxy = @runtime.evaluate("x = { foo: 'fooval', bar: 'barval' }; x[0] = 42; x")
154
+ values = {}
155
+
156
+ proxy.each { |k, v| values[k] = v }
157
+ assert_equal({ 'foo' => 'fooval', 'bar' => 'barval', 0 => 42 }, values)
158
+ end
159
+
160
+ def test_each_passes_an_exception
161
+ proxy = @runtime.evaluate("x = { foo: 'fooval', bar: 'barval' }; x[0] = 42; x")
162
+ values = {}
163
+
164
+ assert_raise(RuntimeError) do
165
+ proxy.each do |k, v|
166
+ values[k] = v
167
+ raise "splat" if values.keys.size == 2
168
+ end
169
+ end
170
+ assert_equal({ 'foo' => 'fooval', 'bar' => 'barval' }, values)
171
+ end
172
+
173
+ def test_is_enumerable
174
+ proxy = @runtime.evaluate("[1, 2, 3]")
175
+ assert_kind_of(Enumerable, proxy)
176
+
177
+ assert_equal([2, 4, 6], proxy.collect { |n| n * 2 })
178
+ end
179
+
180
+ def test_has_a_length
181
+ proxy = @runtime.evaluate("[1, 2, 3]")
182
+ assert_equal(3, proxy.length)
183
+ end
184
+
185
+ def test_length_is_aliased_as_size
186
+ proxy = @runtime.evaluate("[1, 2, 3]")
187
+ assert_equal(3, proxy.size)
188
+ end
189
+
190
+ def test_length_for_arrays_ignores_non_numeric_properties
191
+ proxy = @runtime.evaluate("x = [1, 2, 3]; x['foo'] = 'bar'; x")
192
+ assert_equal(3, proxy.length)
193
+ end
194
+
195
+ def test_length_for_objects_includes_all_properties
196
+ proxy = @runtime.evaluate("x = { foo: 'foo', bar: 'bar', 0: 42 }")
197
+ assert_equal(3, proxy.length)
198
+ end
199
+
200
+ def test_raises_in_js
201
+ err = RuntimeError.new("an exception")
202
+ asplode = lambda { raise err }
203
+ assert_js_equal(err, "x = null; try { foo(); } catch(ex) { x = ex; }; x", :foo => asplode)
204
+ end
205
+
206
+ # FIXME: If you uncomment this test, we get this error:
207
+ #
208
+ # JS API usage error: the address passed to JS_AddNamedRoot currently holds an
209
+ # invalid jsval. This is usually caused by a missing call to JS_RemoveRoot.
210
+ # The root's name is "ruby_land_proxy.c[210]:native_call: proxy_value".
211
+ # Assertion failure: root_points_to_gcArenaList, at jsgc.c:2618
212
+ #
213
+ # WTF?
214
+ #
215
+ # -Aaron
216
+ #
217
+ #def test_throwing_in_js_goes_to_ruby
218
+ # func = @runtime.evaluate('function () { throw "foo"; }')
219
+ # assert_raise(Johnson::Error) {
220
+ # func.call
221
+ # }
222
+ #end
223
+ end
224
+ end
225
+ end
@@ -0,0 +1,17 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "/../../helper"))
2
+
3
+ module Johnson
4
+ module SpiderMonkey
5
+ class RuntimeTest < Johnson::TestCase
6
+ def setup
7
+ @runtime = Johnson::SpiderMonkey::Runtime.new
8
+ end
9
+
10
+ def test_can_create_more_than_one_without_barfing
11
+ assert_nothing_raised {
12
+ Johnson::SpiderMonkey::Runtime.new
13
+ }
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "/../helper"))
2
+
3
+ module Johnson
4
+ class VersionTest < Johnson::TestCase
5
+ def test_has_a_version
6
+ assert_not_nil(Johnson::VERSION)
7
+ end
8
+
9
+ def test_has_a_spidermonkey_version
10
+ assert_not_nil(Johnson::SpiderMonkey::VERSION)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,39 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "/../../helper"))
2
+
3
+ class DotVisitorTest < Test::Unit::TestCase
4
+ def test_var_foo
5
+ dot = Johnson.parse('var foo;').to_dot
6
+ assert_equal(3, dot.nodes.length)
7
+ assert_equal(2, dot.links.length)
8
+ end
9
+
10
+ def test_for
11
+ dot = Johnson.parse('for(var x = 0; x < 10; x++) { }').to_dot
12
+ assert_equal(12, dot.nodes.length)
13
+ assert_equal(11, dot.links.length)
14
+ end
15
+
16
+ def test_for_in
17
+ dot = Johnson.parse('for(var x in johnson(1,2,"asdf")) { }').to_dot
18
+ assert_equal(11, dot.nodes.length)
19
+ assert_equal(10, dot.links.length)
20
+ end
21
+
22
+ def test_try
23
+ dot = Johnson.parse('try { var x = 10; } finally { var x = 20; }').to_dot
24
+ assert_equal(12, dot.nodes.length)
25
+ assert_equal(11, dot.links.length)
26
+ end
27
+
28
+ def test_try_catch
29
+ dot = Johnson.parse('try { var x = 10; } catch(a) { var x = 20; x++; }').to_dot
30
+ assert_equal(16, dot.nodes.length)
31
+ assert_equal(15, dot.links.length)
32
+ end
33
+
34
+ def test_function
35
+ dot = Johnson.parse("var foo = function(a,b) { }").to_dot
36
+ assert_equal(6, dot.nodes.length)
37
+ assert_equal(5, dot.links.length)
38
+ end
39
+ end
@@ -0,0 +1,12 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "/../../helper"))
2
+
3
+ class EnumeratingVisitorTest < Test::Unit::TestCase
4
+ def test_for
5
+ ast = Johnson.parse('for(var x = 0; x < 10; x++) { }')
6
+ counter = 0
7
+ ast.each do |node|
8
+ counter += 1
9
+ end
10
+ assert_equal(12, counter)
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "helper"))
2
+
3
+ class JohnsonTest < Test::Unit::TestCase
4
+ def test_shortcut_evaluate
5
+ assert_equal(4, Johnson.evaluate("2 + 2"))
6
+ end
7
+
8
+ def test_can_provide_context_vars_to_evaluate
9
+ assert_equal(4, Johnson.evaluate("2 + foo", :foo => 2))
10
+ end
11
+
12
+ def test_evaluate_uses_a_new_runtime_each_time
13
+ assert_equal(4, Johnson.evaluate("foo", :foo => 4))
14
+ assert_raise(Johnson::Error) { Johnson.evaluate("foo") }
15
+ end
16
+ end
@@ -0,0 +1,27 @@
1
+ // Init
2
+ Johnson.require("johnson/browser");
3
+ Johnson.require("johnson/browser/jquery");
4
+
5
+ Johnson.waitForThreads = function() {
6
+ // FIXME: This sucks ass
7
+ Ruby.eval("(Thread.list - [Thread.main]).each {|t| t.join}");
8
+ };
9
+
10
+ window.location = "file://" + Ruby.File.expand_path(Ruby.Dir.pwd()) + "/test/assets/jquery_test.html";
11
+ Ruby.eval("(Thread.list - [Thread.main]).each {|t| t.join}");
12
+
13
+ // Load the test runner
14
+ Johnson.require("test/jquery_units/test_helper.js");
15
+
16
+ Johnson.require("test/jquery_units/units/core.js");
17
+ // // Load the tests
18
+ // load(
19
+ // "test/unit/core.js",
20
+ // "test/unit/selector.js",
21
+ // "test/unit/event.js"
22
+ // //"test/unit/fx.js",
23
+ // //"test/unit/ajax.js"
24
+ // );
25
+
26
+ // Display the results
27
+ results();
@@ -0,0 +1,197 @@
1
+ function test(name, fn){
2
+ expected = -1;
3
+ numTests = 0;
4
+ reset();
5
+
6
+ fn();
7
+
8
+ if ( expected != -1 && expected != numTests )
9
+ log( false, "Wrong number of tests run. " + numTests + " ran, expected " + expected );
10
+ }
11
+
12
+ var orig = document.getElementById('main').innerHTML;
13
+
14
+ /**
15
+ * Resets the test setup. Useful for tests that modify the DOM.
16
+ */
17
+ function reset() {
18
+ document.getElementById('main').innerHTML = orig;
19
+ }
20
+
21
+ var currentModule = "";
22
+
23
+ // call on start of module test to prepend name to all tests
24
+ function module(moduleName) {
25
+ currentModule = moduleName;
26
+ }
27
+
28
+ var expected = -1;
29
+
30
+ /**
31
+ * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
32
+ */
33
+ function expect(asserts) {
34
+ expected = asserts;
35
+ }
36
+
37
+ /**
38
+ * Asserts true.
39
+ * @example ok( $("a").size() > 5, "There must be at least 5 anchors" );
40
+ */
41
+ function ok(a, msg) {
42
+ log( !!a, msg );
43
+ }
44
+
45
+ /**
46
+ * Asserts that two arrays are the same
47
+ */
48
+ function isSet(a, b, msg) {
49
+ var ret = true;
50
+ if ( a && b && a.length != undefined && a.length == b.length ) {
51
+ for ( var i = 0; i < a.length; i++ ) {
52
+ if ( a[i] != b[i] )
53
+ ret = false;
54
+ }
55
+ } else
56
+ ret = false;
57
+ if ( !ret )
58
+ log( ret, msg + " expected: " + serialArray(b) + " result: " + serialArray(a) );
59
+ else
60
+ log( ret, msg );
61
+ }
62
+
63
+ /**
64
+ * Asserts that two objects are equivalent
65
+ */
66
+ function isObj(a, b, msg) {
67
+ var ret = true;
68
+
69
+ if ( a && b ) {
70
+ for ( var i in a )
71
+ if ( a[i] != b[i] )
72
+ ret = false;
73
+
74
+ for ( i in b )
75
+ if ( a[i] != b[i] )
76
+ ret = false;
77
+ } else
78
+ ret = false;
79
+
80
+ log( ret, msg );
81
+ }
82
+
83
+ function serialArray( a ) {
84
+ var r = [];
85
+
86
+ if ( a && a.length )
87
+ for ( var i = 0; i < a.length; i++ ) {
88
+ var str = a[i] ? a[i].nodeName : "";
89
+ if ( str ) {
90
+ str = str.toLowerCase();
91
+ if ( a[i].id )
92
+ str += "#" + a[i].id;
93
+ } else
94
+ str = a[i];
95
+ r.push( str );
96
+ }
97
+
98
+ return "[ " + r.join(", ") + " ]"
99
+ }
100
+
101
+ /**
102
+ * Returns an array of elements with the given IDs, eg.
103
+ * @example q("main", "foo", "bar")
104
+ * @result [<div id="main">, <span id="foo">, <input id="bar">]
105
+ */
106
+ function q() {
107
+ var r = [];
108
+ for ( var i = 0; i < arguments.length; i++ )
109
+ r.push( document.getElementById( arguments[i] ) );
110
+ return r;
111
+ }
112
+
113
+ /**
114
+ * Asserts that a select matches the given IDs
115
+ * @example t("Check for something", "//[a]", ["foo", "baar"]);
116
+ * @result returns true if "//[a]" return two elements with the IDs 'foo' and 'baar'
117
+ */
118
+ function t(a,b,c) {
119
+ var f = jQuery(b);
120
+ var s = "";
121
+ for ( var i = 0; i < f.length; i++ )
122
+ s += (s && ",") + '"' + f[i].id + '"';
123
+ isSet(f, q.apply(q,c), a + " (" + b + ")");
124
+ }
125
+
126
+ /**
127
+ * Checks that the first two arguments are equal, with an optional message.
128
+ * Prints out both expected and actual values on failure.
129
+ *
130
+ * Prefered to ok( expected == actual, message )
131
+ *
132
+ * @example equals( "Expected 2 characters.", v.formatMessage("Expected {0} characters.", 2) );
133
+ *
134
+ * @param Object expected
135
+ * @param Object actual
136
+ * @param String message (optional)
137
+ */
138
+ function equals(expected, actual, message) {
139
+ var result = expected == actual;
140
+ message = message || (result ? "okay" : "failed");
141
+ log( result, result ? message + ": " + expected : message + " expected: " + expected + " actual: " + actual );
142
+ }
143
+
144
+ var numTests = 0, total = 0, pass = 0, fail = 0;
145
+
146
+ function log(state, msg){
147
+ print( (state ? "PASS" : "FAIL") + " (" + (++total) + ") " +
148
+ (currentModule ? "[" + currentModule + "] " : "") + msg );
149
+
150
+ numTests++;
151
+
152
+ if ( state )
153
+ pass++;
154
+ else
155
+ fail++;
156
+ }
157
+
158
+ function results(){
159
+ print( pass + " Passed, " + fail + " Failed" );
160
+ }
161
+
162
+ function start(){}
163
+ function stop(){}
164
+
165
+ /**
166
+ * Trigger an event on an element.
167
+ *
168
+ * @example triggerEvent( document.body, "click" );
169
+ *
170
+ * @param DOMElement elem
171
+ * @param String type
172
+ */
173
+ function triggerEvent( elem, type, event ) {
174
+ /*
175
+ if ( jQuery.browser.mozilla || jQuery.browser.opera ) {
176
+ event = document.createEvent("MouseEvents");
177
+ event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
178
+ 0, 0, 0, 0, 0, false, false, false, false, 0, null);
179
+ elem.dispatchEvent( event );
180
+ } else if ( jQuery.browser.msie ) {
181
+ elem.fireEvent("on"+type);
182
+ }
183
+ */
184
+ }
185
+
186
+ /**
187
+ * Add random number to url to stop IE from caching
188
+ *
189
+ * @example url("data/test.html")
190
+ * @result "data/test.html?10538358428943"
191
+ *
192
+ * @example url("data/test.php?foo=bar")
193
+ * @result "data/test.php?foo=bar&10538358345554"
194
+ */
195
+ function url(value) {
196
+ return value + (/\?/.test(value) ? "&" : "?") + new Date().getTime() + "" + parseInt(Math.random()*100000);
197
+ }