Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Using cannonical conformance tests now

  • Loading branch information...
commit 6f057502257acaee21f485b682ca3e200dc2bcec 1 parent 0eef7ef
@fd authored
Showing with 346 additions and 569 deletions.
  1. +3 −0  .gitmodules
  2. +179 −44 lib/json_select/selector_parser.rb
  3. +9 −2 lib/json_select/selector_parser.tt
  4. +93 −44 spec/conformance_spec.rb
  5. +0 −14 spec/fixtures/README.md
  6. +0 −31 spec/fixtures/alltests.txt
  7. +0 −31 spec/fixtures/basic.json
  8. +0 −31 spec/fixtures/basic.xml
  9. +0 −14 spec/fixtures/basic_children.ast
  10. +0 −1  spec/fixtures/basic_children.output
  11. +0 −13 spec/fixtures/basic_combination.ast
  12. +0 −1  spec/fixtures/basic_combination.output
  13. +0 −11 spec/fixtures/basic_first-child.ast
  14. +0 −2  spec/fixtures/basic_first-child.output
  15. +0 −22 spec/fixtures/basic_grouping.ast
  16. +0 −4 spec/fixtures/basic_grouping.output
  17. +0 −7 spec/fixtures/basic_id.ast
  18. +0 −1  spec/fixtures/basic_id.output
  19. +0 −7 spec/fixtures/basic_id_multiple.ast
  20. +0 −3  spec/fixtures/basic_id_multiple.output
  21. +0 −7 spec/fixtures/basic_id_quotes.ast
  22. +0 −2  spec/fixtures/basic_id_quotes.output
  23. +0 −10 spec/fixtures/basic_id_with_type.ast
  24. +0 −1  spec/fixtures/basic_id_with_type.output
  25. +0 −11 spec/fixtures/basic_last-child.ast
  26. +0 −2  spec/fixtures/basic_last-child.output
  27. +0 −11 spec/fixtures/basic_nth-child-2.ast
  28. +0 −4 spec/fixtures/basic_nth-child-2.output
  29. +0 −11 spec/fixtures/basic_nth-child.ast
  30. +0 −3  spec/fixtures/basic_nth-child.output
  31. +0 −11 spec/fixtures/basic_nth-last-child.ast
  32. +0 −2  spec/fixtures/basic_nth-last-child.output
  33. +0 −6 spec/fixtures/basic_root_pseudo.ast
  34. +0 −31 spec/fixtures/basic_root_pseudo.output
  35. +0 −7 spec/fixtures/basic_type.ast
  36. +0 −14 spec/fixtures/basic_type.output
  37. +0 −7 spec/fixtures/basic_type2.ast
  38. +0 −1  spec/fixtures/basic_type2.output
  39. +0 −7 spec/fixtures/basic_type3.ast
  40. +0 −47 spec/fixtures/basic_type3.output
  41. +0 −5 spec/fixtures/basic_universal.ast
  42. +0 −86 spec/fixtures/basic_universal.output
  43. +1 −0  spec/fixtures/conformance
  44. 0  spec/fixtures/{basic_children.selector.out → parser/level_1/basic_children.output}
  45. 0  spec/fixtures/{ → parser/level_1}/basic_children.selector
  46. 0  spec/fixtures/{basic_combination.selector.out → parser/level_1/basic_combination.output}
  47. 0  spec/fixtures/{ → parser/level_1}/basic_combination.selector
  48. 0  spec/fixtures/{basic_first-child.selector.out → parser/level_1/basic_first-child.output}
  49. 0  spec/fixtures/{ → parser/level_1}/basic_first-child.selector
  50. 0  spec/fixtures/{basic_grouping.selector.out → parser/level_1/basic_grouping.output}
  51. 0  spec/fixtures/{ → parser/level_1}/basic_grouping.selector
  52. 0  spec/fixtures/{basic_id.selector.out → parser/level_1/basic_id.output}
  53. 0  spec/fixtures/{ → parser/level_1}/basic_id.selector
  54. 0  spec/fixtures/{basic_id_multiple.selector.out → parser/level_1/basic_id_multiple.output}
  55. 0  spec/fixtures/{ → parser/level_1}/basic_id_multiple.selector
  56. 0  spec/fixtures/{basic_id_quotes.selector.out → parser/level_1/basic_id_quotes.output}
  57. 0  spec/fixtures/{ → parser/level_1}/basic_id_quotes.selector
  58. 0  spec/fixtures/{basic_id_with_type.selector.out → parser/level_1/basic_id_with_type.output}
  59. 0  spec/fixtures/{ → parser/level_1}/basic_id_with_type.selector
  60. 0  spec/fixtures/{basic_nth-last-child.selector.out → parser/level_1/basic_last-child.output}
  61. 0  spec/fixtures/{ → parser/level_1}/basic_last-child.selector
  62. 0  spec/fixtures/{basic_nth-child-2.selector.out → parser/level_1/basic_nth-child-2.output}
  63. 0  spec/fixtures/{ → parser/level_1}/basic_nth-child-2.selector
  64. 0  spec/fixtures/{basic_nth-child.selector.out → parser/level_1/basic_nth-child.output}
  65. 0  spec/fixtures/{ → parser/level_1}/basic_nth-child.selector
  66. 0  spec/fixtures/{basic_last-child.selector.out → parser/level_1/basic_nth-last-child.output}
  67. 0  spec/fixtures/{ → parser/level_1}/basic_nth-last-child.selector
  68. 0  spec/fixtures/{basic_root_pseudo.selector.out → parser/level_1/basic_root_pseudo.output}
  69. 0  spec/fixtures/{ → parser/level_1}/basic_root_pseudo.selector
  70. 0  spec/fixtures/{basic_type.selector.out → parser/level_1/basic_type.output}
  71. 0  spec/fixtures/{ → parser/level_1}/basic_type.selector
  72. 0  spec/fixtures/{basic_type2.selector.out → parser/level_1/basic_type2.output}
  73. 0  spec/fixtures/{ → parser/level_1}/basic_type2.selector
  74. 0  spec/fixtures/{basic_type3.selector.out → parser/level_1/basic_type3.output}
  75. 0  spec/fixtures/{ → parser/level_1}/basic_type3.selector
  76. 0  spec/fixtures/{basic_universal.selector.out → parser/level_1/basic_universal.output}
  77. 0  spec/fixtures/{ → parser/level_1}/basic_universal.selector
  78. +1 −0  spec/fixtures/parser/level_3/basic_has-sans-paren.output
  79. +2 −0  spec/fixtures/parser/level_3/basic_has-sans-paren.selector
  80. +1 −0  spec/fixtures/parser/level_3/basic_has-whitespace.output
  81. +3 −0  spec/fixtures/parser/level_3/basic_has-whitespace.selector
  82. +1 −0  spec/fixtures/parser/level_3/basic_has.output
  83. +1 −0  spec/fixtures/parser/level_3/basic_has.selector
  84. +52 −0 spec/parser_spec.rb
View
3  .gitmodules
@@ -0,0 +1,3 @@
+[submodule "spec/fixtures/conformance"]
+ path = spec/fixtures/conformance
+ url = git://github.com/lloyd/JSONSelectTests.git
View
223 lib/json_select/selector_parser.rb
@@ -619,7 +619,18 @@ def a
end
def e
- elements[4]
+ elements[5]
+ end
+
+ end
+
+ module Pseudo2
+ def a
+ elements[1]
+ end
+
+ def s
+ elements[5]
end
end
@@ -669,53 +680,66 @@ def _nt_pseudo
end
s4 << r5
if r5
- r6 = _nt_pseudo_function_name
+ r6 = _nt_positional_pseudo_function_name
s4 << r6
if r6
- if has_terminal?('(', false, index)
- r7 = instantiate_node(SyntaxNode,input, index...(index + 1))
- @index += 1
- else
- terminal_parse_failure('(')
- r7 = nil
+ s7, i7 = [], index
+ loop do
+ r8 = _nt_ws
+ if r8
+ s7 << r8
+ else
+ break
+ end
end
+ r7 = instantiate_node(SyntaxNode,input, i7...index, s7)
s4 << r7
if r7
- s8, i8 = [], index
- loop do
- r9 = _nt_ws
- if r9
- s8 << r9
- else
- break
- end
+ if has_terminal?('(', false, index)
+ r9 = instantiate_node(SyntaxNode,input, index...(index + 1))
+ @index += 1
+ else
+ terminal_parse_failure('(')
+ r9 = nil
end
- r8 = instantiate_node(SyntaxNode,input, i8...index, s8)
- s4 << r8
- if r8
- r10 = _nt_expression
+ s4 << r9
+ if r9
+ s10, i10 = [], index
+ loop do
+ r11 = _nt_ws
+ if r11
+ s10 << r11
+ else
+ break
+ end
+ end
+ r10 = instantiate_node(SyntaxNode,input, i10...index, s10)
s4 << r10
if r10
- s11, i11 = [], index
- loop do
- r12 = _nt_ws
- if r12
- s11 << r12
- else
- break
- end
- end
- r11 = instantiate_node(SyntaxNode,input, i11...index, s11)
- s4 << r11
- if r11
- if has_terminal?(')', false, index)
- r13 = instantiate_node(SyntaxNode,input, index...(index + 1))
- @index += 1
- else
- terminal_parse_failure(')')
- r13 = nil
+ r12 = _nt_expression
+ s4 << r12
+ if r12
+ s13, i13 = [], index
+ loop do
+ r14 = _nt_ws
+ if r14
+ s13 << r14
+ else
+ break
+ end
end
+ r13 = instantiate_node(SyntaxNode,input, i13...index, s13)
s4 << r13
+ if r13
+ if has_terminal?(')', false, index)
+ r15 = instantiate_node(SyntaxNode,input, index...(index + 1))
+ @index += 1
+ else
+ terminal_parse_failure(')')
+ r15 = nil
+ end
+ s4 << r15
+ end
end
end
end
@@ -732,8 +756,95 @@ def _nt_pseudo
if r4
r0 = r4
else
- @index = i0
- r0 = nil
+ i16, s16 = index, []
+ if has_terminal?(':', false, index)
+ r17 = instantiate_node(SyntaxNode,input, index...(index + 1))
+ @index += 1
+ else
+ terminal_parse_failure(':')
+ r17 = nil
+ end
+ s16 << r17
+ if r17
+ r18 = _nt_subselector_pseudo_function_name
+ s16 << r18
+ if r18
+ s19, i19 = [], index
+ loop do
+ r20 = _nt_ws
+ if r20
+ s19 << r20
+ else
+ break
+ end
+ end
+ r19 = instantiate_node(SyntaxNode,input, i19...index, s19)
+ s16 << r19
+ if r19
+ if has_terminal?('(', false, index)
+ r21 = instantiate_node(SyntaxNode,input, index...(index + 1))
+ @index += 1
+ else
+ terminal_parse_failure('(')
+ r21 = nil
+ end
+ s16 << r21
+ if r21
+ s22, i22 = [], index
+ loop do
+ r23 = _nt_ws
+ if r23
+ s22 << r23
+ else
+ break
+ end
+ end
+ r22 = instantiate_node(SyntaxNode,input, i22...index, s22)
+ s16 << r22
+ if r22
+ r24 = _nt_selectors_group
+ s16 << r24
+ if r24
+ s25, i25 = [], index
+ loop do
+ r26 = _nt_ws
+ if r26
+ s25 << r26
+ else
+ break
+ end
+ end
+ r25 = instantiate_node(SyntaxNode,input, i25...index, s25)
+ s16 << r25
+ if r25
+ if has_terminal?(')', false, index)
+ r27 = instantiate_node(SyntaxNode,input, index...(index + 1))
+ @index += 1
+ else
+ terminal_parse_failure(')')
+ r27 = nil
+ end
+ s16 << r27
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ if s16.last
+ r16 = instantiate_node(JSONSelect::Ast::PseudoSelector,input, i16...index, s16)
+ r16.extend(Pseudo2)
+ else
+ @index = i16
+ r16 = nil
+ end
+ if r16
+ r0 = r16
+ else
+ @index = i0
+ r0 = nil
+ end
end
end
@@ -817,10 +928,10 @@ def _nt_pseudo_class_name
r0
end
- def _nt_pseudo_function_name
+ def _nt_positional_pseudo_function_name
start_index = index
- if node_cache[:pseudo_function_name].has_key?(index)
- cached = node_cache[:pseudo_function_name][index]
+ if node_cache[:positional_pseudo_function_name].has_key?(index)
+ cached = node_cache[:positional_pseudo_function_name][index]
if cached
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
@index = cached.interval.end
@@ -854,7 +965,31 @@ def _nt_pseudo_function_name
end
end
- node_cache[:pseudo_function_name][start_index] = r0
+ node_cache[:positional_pseudo_function_name][start_index] = r0
+
+ r0
+ end
+
+ def _nt_subselector_pseudo_function_name
+ start_index = index
+ if node_cache[:subselector_pseudo_function_name].has_key?(index)
+ cached = node_cache[:subselector_pseudo_function_name][index]
+ if cached
+ cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
+ @index = cached.interval.end
+ end
+ return cached
+ end
+
+ if has_terminal?('has', false, index)
+ r0 = instantiate_node(SyntaxNode,input, index...(index + 3))
+ @index += 3
+ else
+ terminal_parse_failure('has')
+ r0 = nil
+ end
+
+ node_cache[:subselector_pseudo_function_name][start_index] = r0
r0
end
View
11 lib/json_select/selector_parser.tt
@@ -63,7 +63,8 @@ grammar JSONSelectSelector
# ;
rule pseudo
( ':' a:pseudo_class_name <JSONSelect::Ast::PseudoSelector> ) /
- ( ':' a:pseudo_function_name '(' ws* e:expression ws* ')' <JSONSelect::Ast::PseudoSelector> )
+ ( ':' a:positional_pseudo_function_name ws* '(' ws* e:expression ws* ')' <JSONSelect::Ast::PseudoSelector> ) /
+ ( ':' a:subselector_pseudo_function_name ws* '(' ws* s:selectors_group ws* ')' <JSONSelect::Ast::PseudoSelector> )
end
# pseudo_class_name
@@ -74,10 +75,16 @@ grammar JSONSelectSelector
# pseudo_function_name
# : `nth-child` | `nth-last-child`
- rule pseudo_function_name
+ rule positional_pseudo_function_name
'nth-child' / 'nth-last-child'
end
+ # pseudo_function_name
+ # : `nth-child` | `nth-last-child`
+ rule subselector_pseudo_function_name
+ 'has'
+ end
+
# expression
# /* expression is and of the form "an+b" */
# : TODO
View
137 spec/conformance_spec.rb
@@ -1,62 +1,111 @@
describe "JSONSelect", "conformance" do
- %w( basic ).each do |test|
- selectors = "../fixtures/#{test}_*.selector"
- selectors = Dir[File.expand_path(selectors, __FILE__)]
+ p_levels = "../fixtures/conformance/level_*"
+ p_groups = "{basic}.json"
- describe "(#{test})" do
+ levels = {}
- let(:input) do
- path = File.expand_path("../fixtures/#{test}.json", __FILE__)
- Yajl::Parser.parse(File.read(path))
- end
+ d = Dir[File.expand_path(p_levels, __FILE__)]
+ d.each do |dir|
+ level = (levels[File.basename(dir)] = {})
- selectors.each do |selector|
- basename = File.basename(selector, '.selector')
- name = basename[(test.size + 1)..-1]
- output = File.expand_path("../fixtures/#{basename}.output", __FILE__)
- ast = File.expand_path("../fixtures/#{basename}.ast", __FILE__)
- selector_o = File.expand_path("../fixtures/#{basename}.selector.out", __FILE__)
+ d = Dir[File.expand_path(p_groups, dir)]
+ d.each do |json|
+ gname = File.basename(json, '.json')
+ group = (level[gname] = {})
+ group[:json] = json
- describe "(#{name})" do
+ d = Dir[File.expand_path("../#{gname}_*.selector", json)]
+ d.each do |selector|
+ name = File.basename(selector, '.selector').split('_', 2).last
- it "parses the selector" do
- ast = Yajl::Parser.parse(File.read(ast))
- s = JSONSelect(File.read(selector).strip)
- s.should be_a(JSONSelect)
- Yajl::Parser.parse(Yajl::Encoder.encode(s.ast)).should == ast
- end
+ group[name] = [selector,
+ File.expand_path("../#{gname}_#{name}.output", selector)]
+ end
+ end
+ end
- it "produces the correct output" do
- s = JSONSelect(File.read(selector).strip)
- e = []
- Yajl::Parser.parse(File.read(output)) { |o| e << o }
- s.matches(input).should == e
- end
+ levels.each do |level, groups|
+ describe "(#{level})" do
+ groups.each do |group, tests|
+ describe "(#{group})" do
+ input_p = tests.delete(:json)
- it "produces the correct selector" do
- s = JSONSelect(File.read(selector).strip)
- e = File.read(selector_o)
- s.to_s.should == e
+ let(:input) do
+ Yajl::Parser.parse(File.read(input_p))
end
- it "finds the first matching child" do
- s = JSONSelect(File.read(selector).strip)
- e = []
- Yajl::Parser.parse(File.read(output)) { |o| e << o }
- s.match(input).should == e.first
- end
+ tests.each do |test, (selector_p, output_p)|
+ describe "(#{test})" do
- it "can correctly test the object" do
- s = JSONSelect(File.read(selector).strip)
- e = []
- Yajl::Parser.parse(File.read(output)) { |o| e << o }
- s.test(input).should be_true
- end
+ let(:selector) do
+ File.read(selector_p)
+ end
+ let(:output) do
+ o = File.read(output_p)
+ o.sub! /^172$/, "172\n\"ignored object\""
+
+ e = []
+ Yajl::Parser.parse(o) { |o| e << o }
+ e
+ end
+
+ it "finds all matching children" do
+ JSONSelect(selector).matches(input).should == output
+ end
+
+ it "finds the first matching child" do
+ JSONSelect(selector).match(input).should == output.first
+ end
+
+ it "can correctly test the object" do
+ JSONSelect(selector).test(input).should be_true
+ end
+
+ end
+ end
end
end
-
end
end
+
+ # %w( basic ).each do |test|
+ # selectors = "../fixtures/#{test}_*.selector"
+ # selectors = Dir[File.expand_path(selectors, __FILE__)]
+ #
+ # describe "(#{test})" do
+ #
+ # let(:input) do
+ # path = File.expand_path("../fixtures/#{test}.json", __FILE__)
+ # Yajl::Parser.parse(File.read(path))
+ # end
+ #
+ # selectors.each do |selector|
+ # basename = File.basename(selector, '.selector')
+ # name = basename[(test.size + 1)..-1]
+ # output = File.expand_path("../fixtures/#{basename}.output", __FILE__)
+ # # ast = File.expand_path("../fixtures/#{basename}.ast", __FILE__)
+ # selector_o = File.expand_path("../fixtures/#{basename}.selector.out", __FILE__)
+ #
+ # describe "(#{name})" do
+ #
+ # # it "parses the selector" do
+ # # ast = Yajl::Parser.parse(File.read(ast))
+ # # s = JSONSelect(File.read(selector).strip)
+ # # s.should be_a(JSONSelect)
+ # # Yajl::Parser.parse(Yajl::Encoder.encode(s.ast)).should == ast
+ # # end
+ #
+ # # it "produces the correct selector" do
+ # # s = JSONSelect(File.read(selector).strip)
+ # # e = File.read(selector_o)
+ # # s.to_s.should == e
+ # # end
+ #
+ # end
+ # end
+ #
+ # end
+ # end
end
View
14 spec/fixtures/README.md
@@ -1,14 +0,0 @@
-## JSONSelect Conformance Tests.
-
-Test documents have a suffix of `.json`, like `basic.json`.
-
-Selectors to be applied to test documents have the document name,
-followed by an underbar, followed by a description of the test, with
-a `.selector` file name suffix, like `basic_grouping.selector`.
-
-Expected output files have the same name as the `.selector` file,
-but have a `.output` suffix, like `basic_grouping.output`.
-
-Expected output files contain a stream of JSON objects that are what
-is expected to be produced when a given selector is applied to a given
-document.
View
31 spec/fixtures/alltests.txt
@@ -1,31 +0,0 @@
-basic.json
-basic_first-child.output
-basic_first-child.selector
-basic_grouping.output
-basic_grouping.selector
-basic_id.output
-basic_id.selector
-basic_id_multiple.output
-basic_id_multiple.selector
-basic_id_quotes.output
-basic_id_quotes.selector
-basic_id_with_type.output
-basic_id_with_type.selector
-basic_last-child.output
-basic_last-child.selector
-basic_nth-child-2.output
-basic_nth-child-2.selector
-basic_nth-child.output
-basic_nth-child.selector
-basic_nth-last-child.output
-basic_nth-last-child.selector
-basic_root_pseudo.output
-basic_root_pseudo.selector
-basic_type.output
-basic_type.selector
-basic_type2.output
-basic_type2.selector
-basic_type3.output
-basic_type3.selector
-basic_universal.output
-basic_universal.selector
View
31 spec/fixtures/basic.json
@@ -1,31 +0,0 @@
-{
- "name": {
- "first": "Lloyd",
- "last": "Hilaiel"
- },
- "favoriteColor": "yellow",
- "languagesSpoken": [
- {
- "language": "Bulgarian",
- "level": "advanced"
- },
- {
- "language": "English",
- "level": "native"
- },
- {
- "language": "Spanish",
- "level": "beginner"
- }
- ],
- "seatingPreference": [
- "window",
- "aisle"
- ],
- "drinkPreference": [
- "beer",
- "whiskey",
- "wine"
- ],
- "weight": 172
-}
View
31 spec/fixtures/basic.xml
@@ -1,31 +0,0 @@
-<object>
- <object id="name">
- <string id="first">Lloyd</string>
- <string id="last">Hilaiel</string>
- </object>
- <string id="favoriteColor">yellow</string>
- <array id="languagesSpoken">
- <object>
- <string id="language">Bulgarian</string>
- <string id="level">advanced</string>
- </object>
- <object>
- <string id="language">English</string>
- <string id="level">native</string>
- </object>
- <object>
- <string id="language">Spanish</string>
- <string id="level">beginner</string>
- </object>
- </array>
- <array id="seatingPreference">
- <string>window</string>
- <string>aisle</string>
- </array>
- <array id="drinkPreference">
- <string>beer</string>
- <string>whiskey</string>
- <string>wine</string>
- </array>
- <number id="weight">172</number>
-</object>
View
14 spec/fixtures/basic_children.ast
@@ -1,14 +0,0 @@
-[ { "tests" :
- [ { "f" : "has_class"
- , "n" : "name"
- }
- ]
- }
-, ">"
-, { "tests" :
- [ { "f" : "has_class"
- , "n" : "first"
- }
- ]
- }
-]
View
1  spec/fixtures/basic_children.output
@@ -1 +0,0 @@
-"Lloyd"
View
13 spec/fixtures/basic_combination.ast
@@ -1,13 +0,0 @@
-[ { "tests" :
- [ { "f" : "has_class"
- , "n" : "name"
- }
- ]
- }
-, { "tests" :
- [ { "f" : "has_class"
- , "n" : "first"
- }
- ]
- }
-]
View
1  spec/fixtures/basic_combination.output
@@ -1 +0,0 @@
-"Lloyd"
View
11 spec/fixtures/basic_first-child.ast
@@ -1,11 +0,0 @@
-[ { "tests" :
- [ { "f" : "instance_of_type"
- , "n" : "string"
- }
- , { "f" : "nth_child"
- , "a" : 0
- , "b" : 1
- }
- ]
- }
-]
View
2  spec/fixtures/basic_first-child.output
@@ -1,2 +0,0 @@
-"window"
-"beer"
View
22 spec/fixtures/basic_grouping.ast
@@ -1,22 +0,0 @@
-[ ","
-
-, [ { "tests" :
- [ { "f" : "instance_of_type"
- , "n" : "string"
- }
- , { "f" : "has_class"
- , "n" : "level"
- }
- ]
- }
- ]
-
-, [ { "tests" :
- [ { "f" : "instance_of_type"
- , "n" : "number"
- }
- ]
- }
- ]
-
-]
View
4 spec/fixtures/basic_grouping.output
@@ -1,4 +0,0 @@
-"advanced"
-"native"
-"beginner"
-172
View
7 spec/fixtures/basic_id.ast
@@ -1,7 +0,0 @@
-[ { "tests" :
- [ { "f" : "has_class"
- , "n" : "favoriteColor"
- }
- ]
- }
-]
View
1  spec/fixtures/basic_id.output
@@ -1 +0,0 @@
-"yellow"
View
7 spec/fixtures/basic_id_multiple.ast
@@ -1,7 +0,0 @@
-[ { "tests" :
- [ { "f" : "has_class"
- , "n" : "language"
- }
- ]
- }
-]
View
3  spec/fixtures/basic_id_multiple.output
@@ -1,3 +0,0 @@
-"Bulgarian"
-"English"
-"Spanish"
View
7 spec/fixtures/basic_id_quotes.ast
@@ -1,7 +0,0 @@
-[ { "tests" :
- [ { "f" : "has_class"
- , "n" : "weight"
- }
- ]
- }
-]
View
2  spec/fixtures/basic_id_quotes.output
@@ -1,2 +0,0 @@
-172
-
View
10 spec/fixtures/basic_id_with_type.ast
@@ -1,10 +0,0 @@
-[ { "tests" :
- [ { "f" : "instance_of_type"
- , "n" : "string"
- }
- , { "f" : "has_class"
- , "n" : "favoriteColor"
- }
- ]
- }
-]
View
1  spec/fixtures/basic_id_with_type.output
@@ -1 +0,0 @@
-"yellow"
View
11 spec/fixtures/basic_last-child.ast
@@ -1,11 +0,0 @@
-[ { "tests" :
- [ { "f" : "instance_of_type"
- , "n" : "string"
- }
- , { "f" : "nth_last_child"
- , "a" : 0
- , "b" : 1
- }
- ]
- }
-]
View
2  spec/fixtures/basic_last-child.output
@@ -1,2 +0,0 @@
-"aisle"
-"wine"
View
11 spec/fixtures/basic_nth-child-2.ast
@@ -1,11 +0,0 @@
-[ { "tests" :
- [ { "f" : "instance_of_type"
- , "n" : "string"
- }
- , { "f" : "nth_child"
- , "a" : -1
- , "b" : 2
- }
- ]
- }
-]
View
4 spec/fixtures/basic_nth-child-2.output
@@ -1,4 +0,0 @@
-"window"
-"aisle"
-"beer"
-"whiskey"
View
11 spec/fixtures/basic_nth-child.ast
@@ -1,11 +0,0 @@
-[ { "tests" :
- [ { "f" : "instance_of_type"
- , "n" : "string"
- }
- , { "f" : "nth_child"
- , "a" : 2
- , "b" : 1
- }
- ]
- }
-]
View
3  spec/fixtures/basic_nth-child.output
@@ -1,3 +0,0 @@
-"window"
-"beer"
-"wine"
View
11 spec/fixtures/basic_nth-last-child.ast
@@ -1,11 +0,0 @@
-[ { "tests" :
- [ { "f" : "instance_of_type"
- , "n" : "string"
- }
- , { "f" : "nth_last_child"
- , "a" : 0
- , "b" : 1
- }
- ]
- }
-]
View
2  spec/fixtures/basic_nth-last-child.output
@@ -1,2 +0,0 @@
-"aisle"
-"wine"
View
6 spec/fixtures/basic_root_pseudo.ast
@@ -1,6 +0,0 @@
-[ { "tests" :
- [ { "f" : "is_root"
- }
- ]
- }
-]
View
31 spec/fixtures/basic_root_pseudo.output
@@ -1,31 +0,0 @@
-{
- "name": {
- "first": "Lloyd",
- "last": "Hilaiel"
- },
- "favoriteColor": "yellow",
- "languagesSpoken": [
- {
- "language": "Bulgarian",
- "level": "advanced"
- },
- {
- "language": "English",
- "level": "native"
- },
- {
- "language": "Spanish",
- "level": "beginner"
- }
- ],
- "seatingPreference": [
- "window",
- "aisle"
- ],
- "drinkPreference": [
- "beer",
- "whiskey",
- "wine"
- ],
- "weight": 172
-}
View
7 spec/fixtures/basic_type.ast
@@ -1,7 +0,0 @@
-[ { "tests" :
- [ { "f" : "instance_of_type"
- , "n" : "string"
- }
- ]
- }
-]
View
14 spec/fixtures/basic_type.output
@@ -1,14 +0,0 @@
-"Lloyd"
-"Hilaiel"
-"yellow"
-"Bulgarian"
-"advanced"
-"English"
-"native"
-"Spanish"
-"beginner"
-"window"
-"aisle"
-"beer"
-"whiskey"
-"wine"
View
7 spec/fixtures/basic_type2.ast
@@ -1,7 +0,0 @@
-[ { "tests" :
- [ { "f" : "instance_of_type"
- , "n" : "number"
- }
- ]
- }
-]
View
1  spec/fixtures/basic_type2.output
@@ -1 +0,0 @@
-172
View
7 spec/fixtures/basic_type3.ast
@@ -1,7 +0,0 @@
-[ { "tests" :
- [ { "f" : "instance_of_type"
- , "n" : "object"
- }
- ]
- }
-]
View
47 spec/fixtures/basic_type3.output
@@ -1,47 +0,0 @@
-{
- "first": "Lloyd",
- "last": "Hilaiel"
-}
-{
- "language": "Bulgarian",
- "level": "advanced"
-}
-{
- "language": "English",
- "level": "native"
-}
-{
- "language": "Spanish",
- "level": "beginner"
-}
-{
- "name": {
- "first": "Lloyd",
- "last": "Hilaiel"
- },
- "favoriteColor": "yellow",
- "languagesSpoken": [
- {
- "language": "Bulgarian",
- "level": "advanced"
- },
- {
- "language": "English",
- "level": "native"
- },
- {
- "language": "Spanish",
- "level": "beginner"
- }
- ],
- "seatingPreference": [
- "window",
- "aisle"
- ],
- "drinkPreference": [
- "beer",
- "whiskey",
- "wine"
- ],
- "weight": 172
-}
View
5 spec/fixtures/basic_universal.ast
@@ -1,5 +0,0 @@
-[ { "tests" :
- [
- ]
- }
-]
View
86 spec/fixtures/basic_universal.output
@@ -1,86 +0,0 @@
-"Lloyd"
-"Hilaiel"
-{
- "first": "Lloyd",
- "last": "Hilaiel"
-}
-"yellow"
-"Bulgarian"
-"advanced"
-{
- "language": "Bulgarian",
- "level": "advanced"
-}
-"English"
-"native"
-{
- "language": "English",
- "level": "native"
-}
-"Spanish"
-"beginner"
-{
- "language": "Spanish",
- "level": "beginner"
-}
-[
- {
- "language": "Bulgarian",
- "level": "advanced"
- },
- {
- "language": "English",
- "level": "native"
- },
- {
- "language": "Spanish",
- "level": "beginner"
- }
-]
-"window"
-"aisle"
-[
- "window",
- "aisle"
-]
-"beer"
-"whiskey"
-"wine"
-[
- "beer",
- "whiskey",
- "wine"
-]
-172
-"somehow YAJL swallows the next object after a number"
-{
- "name": {
- "first": "Lloyd",
- "last": "Hilaiel"
- },
- "favoriteColor": "yellow",
- "languagesSpoken": [
- {
- "language": "Bulgarian",
- "level": "advanced"
- },
- {
- "language": "English",
- "level": "native"
- },
- {
- "language": "Spanish",
- "level": "beginner"
- }
- ],
- "seatingPreference": [
- "window",
- "aisle"
- ],
- "drinkPreference": [
- "beer",
- "whiskey",
- "wine"
- ],
- "weight": 172
-}
1  spec/fixtures/conformance
@@ -0,0 +1 @@
+Subproject commit f92f204b86ef7413e97ae356f53bb680d100bbcb
View
0  spec/fixtures/basic_children.selector.out → spec/fixtures/parser/level_1/basic_children.output
File renamed without changes
View
0  spec/fixtures/basic_children.selector → spec/fixtures/parser/level_1/basic_children.selector
File renamed without changes
View
0  spec/fixtures/basic_combination.selector.out → .../fixtures/parser/level_1/basic_combination.output
File renamed without changes
View
0  spec/fixtures/basic_combination.selector → ...ixtures/parser/level_1/basic_combination.selector
File renamed without changes
View
0  spec/fixtures/basic_first-child.selector.out → .../fixtures/parser/level_1/basic_first-child.output
File renamed without changes
View
0  spec/fixtures/basic_first-child.selector → ...ixtures/parser/level_1/basic_first-child.selector
File renamed without changes
View
0  spec/fixtures/basic_grouping.selector.out → spec/fixtures/parser/level_1/basic_grouping.output
File renamed without changes
View
0  spec/fixtures/basic_grouping.selector → spec/fixtures/parser/level_1/basic_grouping.selector
File renamed without changes
View
0  spec/fixtures/basic_id.selector.out → spec/fixtures/parser/level_1/basic_id.output
File renamed without changes
View
0  spec/fixtures/basic_id.selector → spec/fixtures/parser/level_1/basic_id.selector
File renamed without changes
View
0  spec/fixtures/basic_id_multiple.selector.out → .../fixtures/parser/level_1/basic_id_multiple.output
File renamed without changes
View
0  spec/fixtures/basic_id_multiple.selector → ...ixtures/parser/level_1/basic_id_multiple.selector
File renamed without changes
View
0  spec/fixtures/basic_id_quotes.selector.out → spec/fixtures/parser/level_1/basic_id_quotes.output
File renamed without changes
View
0  spec/fixtures/basic_id_quotes.selector → .../fixtures/parser/level_1/basic_id_quotes.selector
File renamed without changes
View
0  spec/fixtures/basic_id_with_type.selector.out → ...fixtures/parser/level_1/basic_id_with_type.output
File renamed without changes
View
0  spec/fixtures/basic_id_with_type.selector → ...xtures/parser/level_1/basic_id_with_type.selector
File renamed without changes
View
0  spec/fixtures/basic_nth-last-child.selector.out → spec/fixtures/parser/level_1/basic_last-child.output
File renamed without changes
View
0  spec/fixtures/basic_last-child.selector → ...fixtures/parser/level_1/basic_last-child.selector
File renamed without changes
View
0  spec/fixtures/basic_nth-child-2.selector.out → .../fixtures/parser/level_1/basic_nth-child-2.output
File renamed without changes
View
0  spec/fixtures/basic_nth-child-2.selector → ...ixtures/parser/level_1/basic_nth-child-2.selector
File renamed without changes
View
0  spec/fixtures/basic_nth-child.selector.out → spec/fixtures/parser/level_1/basic_nth-child.output
File renamed without changes
View
0  spec/fixtures/basic_nth-child.selector → .../fixtures/parser/level_1/basic_nth-child.selector
File renamed without changes
View
0  spec/fixtures/basic_last-child.selector.out → ...xtures/parser/level_1/basic_nth-last-child.output
File renamed without changes
View
0  spec/fixtures/basic_nth-last-child.selector → ...ures/parser/level_1/basic_nth-last-child.selector
File renamed without changes
View
0  spec/fixtures/basic_root_pseudo.selector.out → .../fixtures/parser/level_1/basic_root_pseudo.output
File renamed without changes
View
0  spec/fixtures/basic_root_pseudo.selector → ...ixtures/parser/level_1/basic_root_pseudo.selector
File renamed without changes
View
0  spec/fixtures/basic_type.selector.out → spec/fixtures/parser/level_1/basic_type.output
File renamed without changes
View
0  spec/fixtures/basic_type.selector → spec/fixtures/parser/level_1/basic_type.selector
File renamed without changes
View
0  spec/fixtures/basic_type2.selector.out → spec/fixtures/parser/level_1/basic_type2.output
File renamed without changes
View
0  spec/fixtures/basic_type2.selector → spec/fixtures/parser/level_1/basic_type2.selector
File renamed without changes
View
0  spec/fixtures/basic_type3.selector.out → spec/fixtures/parser/level_1/basic_type3.output
File renamed without changes
View
0  spec/fixtures/basic_type3.selector → spec/fixtures/parser/level_1/basic_type3.selector
File renamed without changes
View
0  spec/fixtures/basic_universal.selector.out → spec/fixtures/parser/level_1/basic_universal.output
File renamed without changes
View
0  spec/fixtures/basic_universal.selector → .../fixtures/parser/level_1/basic_universal.selector
File renamed without changes
View
1  spec/fixtures/parser/level_3/basic_has-sans-paren.output
@@ -0,0 +1 @@
+Error: missing closing paren
View
2  spec/fixtures/parser/level_3/basic_has-sans-paren.selector
@@ -0,0 +1,2 @@
+object:has(.language
+
View
1  spec/fixtures/parser/level_3/basic_has-whitespace.output
@@ -0,0 +1 @@
+object:has(.language)
View
3  spec/fixtures/parser/level_3/basic_has-whitespace.selector
@@ -0,0 +1,3 @@
+object:has ( .language )
+
+
View
1  spec/fixtures/parser/level_3/basic_has.output
@@ -0,0 +1 @@
+object:has(.language)
View
1  spec/fixtures/parser/level_3/basic_has.selector
@@ -0,0 +1 @@
+object:has(.language)
View
52 spec/parser_spec.rb
@@ -0,0 +1,52 @@
+describe "JSONSelect", "parser" do
+
+ p_levels = "../fixtures/parser/level_*"
+ p_groups = %w( basic )
+
+ levels = {}
+
+ d = Dir[File.expand_path(p_levels, __FILE__)]
+ d.each do |dir|
+ level = (levels[File.basename(dir)] = {})
+
+ p_groups.each do |gname|
+ json = File.expand_path(gname, dir)
+ group = (level[gname] = {})
+
+ d = Dir[File.expand_path("../#{gname}_*.selector", json)]
+ d.each do |selector|
+ name = File.basename(selector, '.selector').split('_', 2).last
+
+ group[name] = [selector,
+ File.expand_path("../#{gname}_#{name}.output", selector)]
+ end
+ end
+ end
+
+ levels.each do |level, groups|
+ describe "(#{level})" do
+ groups.each do |group, tests|
+ describe "(#{group})" do
+ tests.each do |test, (selector_p, output_p)|
+ describe "(#{test})" do
+
+ let(:selector) do
+ File.read(selector_p)
+ end
+
+ let(:output) do
+ File.read(output_p)
+ end
+
+ it "produces the correct selector" do
+ JSONSelect(selector).to_s.should == output
+ end
+
+ end
+ end
+ end
+ end
+ end
+ end
+
+end

6 comments on commit 6f05750

@lloyd

How are you finding the broken out conformance tests? How do you feel about the negative tests, those where the .output file contains Error:. Is it useful that actual error messages emitted by the javascript implementation occur in test files, or annoying?

@fd
Owner

I think they are great. The negative tests are less useful but it's easy enough to map the JS error messages to Ruby error messages. Maybe it's a good idea to define standardized error numbers. Like this the tests are not coupled to the JS implementation.

@lloyd

I don't know if I care to regulate how errors are reported in other implementations... But you are the only other implementor at this point, so basically I'm all ears.

One thing I was thinking is to change the extension of negative tests to .error (from .output). This way crazy over zealous implementations could copy the ref impl's js errors verbatim, while others could just check for the existence of the error file to determine whether or not an error was expected.

@fd
Owner

I think changing the extension of the negative tests to .error is better as it makes the test type more explicit.

Also I think that negative tests like this one are not in the right place. I feel that the level_{1,2,3} groups should contain tests about the value-selecting logic not about the parser. A forth group of tests, the parser tests (or maybe level_0), might contain the tests for the parser details (like white space, precedence, parse errors, etc.).

@lloyd

ok, I'll make the change to .error: lloyd/JSONSelectTests#1

I understand the suggestion about level_0, but it would be confusing. level_{123} correspond to conformance levels. Syntax errors in level 3 language constructs have to reside somewhere that they can be filtered out by implementers building level 1 support.

One thing we could do is create subdirectories under the level_{123} directories... perhaps syntax and matching directories. But then that gets into a pretty complicated structure for a fairly simple collection of stuff. what do you think?

@fd
Owner

You're right. Let's just keep the level_0 stuff as it is and when things grow out of controle (which would presumably be in the distant future) we can still add more structure.

Please sign in to comment.
Something went wrong with that request. Please try again.