icss 0.1.3 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/.watchr +35 -3
  2. data/CHANGELOG.md +38 -0
  3. data/Gemfile +19 -14
  4. data/README.md +296 -0
  5. data/Rakefile +2 -6
  6. data/TODO.md +13 -0
  7. data/VERSION +1 -1
  8. data/examples/avro_examples/complicated.icss.yaml +14 -13
  9. data/examples/bnc.icss.yaml +70 -0
  10. data/examples/chronic.icss.yaml +3 -3
  11. data/examples/license.icss.yaml +7 -0
  12. data/examples/source1.icss.yaml +4 -0
  13. data/examples/source2.icss.yaml +4 -0
  14. data/examples/test_icss.yaml +67 -0
  15. data/icss.gemspec +103 -43
  16. data/lib/icss.rb +37 -15
  17. data/lib/icss/core_types.rb +19 -0
  18. data/lib/icss/error.rb +4 -0
  19. data/{init.rb → lib/icss/init.rb} +0 -0
  20. data/lib/icss/message.rb +124 -66
  21. data/lib/icss/message/message_sample.rb +144 -0
  22. data/lib/icss/protocol.rb +184 -131
  23. data/lib/icss/protocol/code_asset.rb +18 -0
  24. data/lib/icss/protocol/data_asset.rb +23 -0
  25. data/lib/icss/protocol/license.rb +41 -0
  26. data/lib/icss/protocol/source.rb +37 -0
  27. data/lib/icss/protocol/target.rb +68 -0
  28. data/lib/icss/receiver_model.rb +24 -0
  29. data/lib/icss/receiver_model/active_model_shim.rb +36 -0
  30. data/lib/icss/receiver_model/acts_as_catalog.rb +170 -0
  31. data/lib/icss/receiver_model/acts_as_hash.rb +177 -0
  32. data/lib/icss/receiver_model/acts_as_loadable.rb +47 -0
  33. data/lib/icss/receiver_model/acts_as_tuple.rb +100 -0
  34. data/lib/icss/receiver_model/locale/en.yml +27 -0
  35. data/lib/icss/receiver_model/to_geo_json.rb +19 -0
  36. data/lib/icss/receiver_model/tree_merge.rb +34 -0
  37. data/lib/icss/receiver_model/validations.rb +31 -0
  38. data/lib/icss/serialization.rb +51 -0
  39. data/lib/icss/serialization/zaml.rb +443 -0
  40. data/lib/icss/type.rb +148 -501
  41. data/lib/icss/type/base_type.rb +0 -0
  42. data/lib/icss/type/named_type.rb +184 -0
  43. data/lib/icss/type/record_field.rb +77 -0
  44. data/lib/icss/type/record_model.rb +49 -0
  45. data/lib/icss/type/record_schema.rb +54 -0
  46. data/lib/icss/type/record_type.rb +325 -0
  47. data/lib/icss/type/simple_types.rb +72 -0
  48. data/lib/icss/type/structured_schema.rb +288 -0
  49. data/lib/icss/type/type_factory.rb +144 -0
  50. data/lib/icss/type/union_schema.rb +41 -0
  51. data/lib/icss/view_helper.rb +56 -19
  52. data/notes/named_array.md +32 -0
  53. data/notes/on_include_vs_extend_etc.rb +176 -0
  54. data/notes/technical_details.md +278 -0
  55. data/spec/core_types_spec.rb +119 -0
  56. data/spec/fixtures/zaml_complex_hash.yaml +35 -0
  57. data/spec/icss_spec.rb +86 -23
  58. data/spec/message/message_sample_spec.rb +4 -0
  59. data/spec/message_spec.rb +139 -0
  60. data/spec/protocol/license_spec.rb +67 -0
  61. data/spec/protocol/protocol_catalog_spec.rb +48 -0
  62. data/spec/protocol/protocol_validations_spec.rb +176 -0
  63. data/spec/protocol/source_spec.rb +65 -0
  64. data/spec/protocol_spec.rb +91 -37
  65. data/spec/receiver_model_spec.rb +111 -0
  66. data/spec/serialization/zaml_spec.rb +81 -0
  67. data/spec/serialization/zaml_test.rb +473 -0
  68. data/spec/serialization_spec.rb +63 -0
  69. data/spec/spec_helper.rb +24 -7
  70. data/spec/support/icss_test_helper.rb +67 -0
  71. data/spec/support/load_example_protocols.rb +17 -0
  72. data/spec/type/base_type_spec.rb +0 -0
  73. data/spec/type/named_type_spec.rb +75 -0
  74. data/spec/type/record_field_spec.rb +44 -0
  75. data/spec/type/record_model_spec.rb +206 -0
  76. data/spec/type/record_schema_spec.rb +161 -0
  77. data/spec/type/record_type_spec.rb +155 -0
  78. data/spec/type/simple_types_spec.rb +121 -0
  79. data/spec/type/structured_schema_spec.rb +300 -0
  80. data/spec/type/type_catalog_spec.rb +44 -0
  81. data/spec/type/type_factory_spec.rb +93 -0
  82. data/spec/type/union_schema_spec.rb +0 -0
  83. data/spec/type_spec.rb +63 -0
  84. metadata +205 -144
  85. data/CHANGELOG.textile +0 -9
  86. data/Gemfile.lock +0 -40
  87. data/README.textile +0 -29
  88. data/lib/icss/brevity.rb +0 -136
  89. data/lib/icss/code_asset.rb +0 -16
  90. data/lib/icss/core_ext.rb +0 -9
  91. data/lib/icss/data_asset.rb +0 -22
  92. data/lib/icss/old.rb +0 -96
  93. data/lib/icss/protocol_set.rb +0 -48
  94. data/lib/icss/sample_message_call.rb +0 -142
  95. data/lib/icss/target.rb +0 -72
  96. data/lib/icss/type/factory.rb +0 -196
  97. data/lib/icss/validations.rb +0 -16
  98. data/spec/validations_spec.rb +0 -171
@@ -0,0 +1,111 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+ require 'icss'
3
+ require ENV.root_path('spec/support/icss_test_helper')
4
+ include IcssTestHelper
5
+
6
+ describe Icss::ReceiverModel do
7
+ before do
8
+ IcssTestHelper.remove_icss_constants('Handy', 'UnderHandy')
9
+ class Icss::Handy < Icss::SmurfModel ; end
10
+ class Icss::UnderHandy < Icss::Handy ; end
11
+ end
12
+
13
+ context 'field validations' do
14
+ before do
15
+ Icss::Handy.field :rangey, Integer, :validates => { :inclusion => { :in => 0..9 }}
16
+ Icss::Handy.field :mandatory, Integer, :validates => { :presence => true }
17
+ Icss::Handy.field :patternish, String, :validates => { :format => { :with => /eat$/ } }
18
+ end
19
+ let(:good_smurf){ Icss::Handy.receive(:rangey => 5, :patternish => 'smurfberry crunch is fun to eat', :mandatory => 1) }
20
+ let(:bad_smurf ){ Icss::Handy.receive(:rangey => 10, :patternish => 'smurfnuggets!') }
21
+
22
+ it 'are applied, and pass when good' do
23
+ good_smurf.should be_valid
24
+ end
25
+
26
+ it 'are applied, and fail when bad' do
27
+ bad_smurf.should_not be_valid
28
+ bad_smurf.errors.should == {
29
+ :rangey => ["is not included in the list"],
30
+ :mandatory => ["can't be blank"],
31
+ :patternish => ["is invalid"]
32
+ }
33
+ bad_smurf.rangey = 3 ; bad_smurf.mandatory = 7 ; bad_smurf.patternish = "a very smurfy breakfast treat"
34
+ bad_smurf.should be_valid
35
+ bad_smurf.errors.should be_empty
36
+ end
37
+
38
+ it 'inherit' do
39
+ under_handy = Icss::UnderHandy.receive(:rangey => -1, :patternish => 'smurfberry crunch is fun to eat', :mandatory => 1)
40
+ under_handy.should_not be_valid
41
+ under_handy.errors.keys.should == [:rangey]
42
+ under_handy.rangey = 1
43
+ under_handy.should be_valid
44
+ end
45
+
46
+ it ':required => true is sugar for ":validates => { :presence => true }"' do
47
+ Icss::Handy.field :also_mandatory, Integer, :required => true
48
+ good_smurf.should_not be_valid
49
+ good_smurf.errors.should == { :also_mandatory => ["can't be blank"], }
50
+ good_smurf.also_mandatory = 88
51
+ good_smurf.should be_valid
52
+ end
53
+ end
54
+
55
+ # context ':index => ' do
56
+ # it 'primary key'
57
+ # it 'foreign key'
58
+ # it 'uniqueness constraint'
59
+ # end
60
+ #
61
+ # # context ':accessor / :reader / :writer' do
62
+ # # it ':private -- attr_whatever is private'
63
+ # # it ':protected -- attr_whatever is protected'
64
+ # # it ':none -- no accessor/reader/writer'
65
+ # # end
66
+ #
67
+ # context ':after_receive'
68
+ #
69
+ # context ':i18n_key'
70
+ # context ':human_name => '
71
+ # context ':singular_name => '
72
+ # context ':plural_name => '
73
+ # context ':uncountable => '
74
+ #
75
+ # context :serialization
76
+ # it '#serializable_hash'
77
+ #
78
+ # # constant
79
+ # # mass assignment security: accessible,
80
+ #
81
+ # it 'works on the parent Meta module type, not '
82
+ #
83
+ #
84
+ # context 'has properties' do
85
+ # it 'described by its #fields'
86
+ #
87
+ # context 'container types' do
88
+ #
89
+ # it 'field foo, Array, :items => FooClass validates instances are is_a?(FooClass)'
90
+ # it 'field foo, Array, :with => FooFactory validates instances are is_a?(FooFactory.product_klass)'
91
+ #
92
+ # it ''
93
+ #
94
+ # end
95
+ # end
96
+ #
97
+ # context 'special properties' do
98
+ # it '_domain_id_field'
99
+ # it '_primary_location_field'
100
+ # it '_slug' # ??
101
+ # end
102
+ #
103
+ # context 'name' do
104
+ # context ':i18n_key'
105
+ # context ':human_name => '
106
+ # context ':singular_name => '
107
+ # context ':plural_name => '
108
+ # context ':uncountable => '
109
+ # end
110
+
111
+ end
@@ -0,0 +1,81 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
+ require 'yaml'
4
+ require 'icss/serialization/zaml'
5
+
6
+ describe ZAML do
7
+ describe '#to_zaml' do
8
+ [nil, :my_sym, true, false, 69, 69.0, /my_regexp/,
9
+ ArgumentError.new('my_exception'),
10
+ 'my_str',
11
+ {'simple' => :hash, :items => {2 => /pairs/}},
12
+ ['arr', :items, 4, /things/], Time.now, (3..69),
13
+ ].each do |obj|
14
+ it "serializes a #{obj.class}" do
15
+ obj.to_zaml.should == obj.to_yaml
16
+ end
17
+ end
18
+ end
19
+
20
+ BASIC_HASH = {
21
+ :name => "a few",
22
+ :nested => "elements",
23
+ :including => "line\nbreaking\nstrings",
24
+ :and_including => "newline terminated\nline\nbreaking\nstrings\n",
25
+ :so => ":what
26
+ :dyathink, :of, :that
27
+ "
28
+ }
29
+
30
+ def complex_hash
31
+ { 'complex' => :hash,
32
+ :items => {2 => /pairs/},
33
+ 'Iñtërnâtiônàlizætiøn' => "look out for 'funny quotes'.",
34
+ :and => [BASIC_HASH, { :name => 'bob' }, [], ],
35
+ }
36
+ end
37
+
38
+ def complex_hash_with_comments
39
+ {
40
+ ZAML::Comment.new("first comment") => 1,
41
+ 'complex' => :hash,
42
+ :items => {2 => /pairs/},
43
+ 'Iñtërnâtiônàlizætiøn' => "look out for 'funny quotes'.",
44
+ :and => [
45
+ ZAML::Comment.new("informative comments"),
46
+ BASIC_HASH,
47
+ ZAML::Comment.new("more informative comments, \nspread across\n multiple lines"),
48
+ {
49
+ :name => 'bob',
50
+ ZAML::Comment.new("comment can be in hash key, \nspread across\n multiple lines;") => :zaml_ignores_their_hash_val
51
+ },
52
+ ZAML.padding(3),
53
+ [ZAML::Comment.new("does the right thing \neven when\nis the only item")],
54
+ ],
55
+ }
56
+ end
57
+
58
+ context 'valign' do
59
+ it 'accepts an option, defaults to nil' do
60
+ obj = ZAML.new(:valign => 24)
61
+ obj.valign.should == 24
62
+ obj = ZAML.new()
63
+ obj.valign.should == nil
64
+ end
65
+
66
+ it 'aligns things' do
67
+ obj = complex_hash_with_comments
68
+ yaml_str = ZAML.dump(obj, '', :valign => 24 )
69
+ # puts yaml_str
70
+ from_yaml = YAML.load(yaml_str)
71
+ from_yaml.should == complex_hash
72
+ end
73
+
74
+ it 'matches sample' do
75
+ expected_yaml_str = File.read(ENV.root_path('spec/fixtures/zaml_complex_hash.yaml'))
76
+ yaml_str = ZAML.dump(complex_hash_with_comments, '', :valign => 24 )
77
+ # puts yaml_str
78
+ yaml_str.should == expected_yaml_str
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,473 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- encoding: utf-8 -*-
3
+
4
+ require 'test/unit'
5
+ require 'yaml'
6
+
7
+ $LOAD_PATH.unshift(File.expand_path('../../lib', File.dirname(__FILE__)))
8
+ require 'icss/serialization/zaml'
9
+
10
+ DICT_WORDS_PATH = '/usr/share/dict/words'
11
+ SLOWNESS = 0 # how acceptably slow are you willing to have the tests take
12
+
13
+ ENCODING_KLUDGE = true # YAML loads in UTF-8, causing strings to compare unequal
14
+ INDENTED_ARRAYS_KLUDGE = true # YAML is uglier about indenting arrays under hashes
15
+ YAML_DUPS_STRINGS_KLUDGE = true # YAML in 1.9 is less aggressive about referencing strings
16
+
17
+ class My_class
18
+ def initialize
19
+ @string = 'string...'
20
+ @self = self
21
+ @do_not_store_me = '*************** SHOULD NOT SHOW UP IN OUTPUT ***************'
22
+ end
23
+ def to_yaml_properties
24
+ ['@string', '@self']
25
+ end
26
+ end
27
+
28
+ class ZamlDumpTest < Test::Unit::TestCase
29
+ #
30
+ # This class and the test helper which follow embody what we mean by YAML compatibility.
31
+ # When we do a round-trip dump->load we expect
32
+ # 1) that the data from ZAML.dump will come back correctly
33
+ # 1a) all vales will be correct
34
+ # 1b) only data that should be dumped is
35
+ # 1c) object identity is preseved
36
+ # 2) if YAML.dump also works by these standards the dumped data should
37
+ # generally look like what yaml.rb produces, minus unneeded whitespace
38
+ # (trailing blanks, etc.)
39
+ class Equivalency < Hash
40
+ attr_reader :result,:message
41
+
42
+ def self.test(a,b)
43
+ new.test(a,b)
44
+ end
45
+ def test(a,b)
46
+ @result = equivalent(a,b)
47
+ self
48
+ end
49
+ def note_failure(msg)
50
+ (@message ||= '') << msg
51
+ false
52
+ end
53
+ def same_class(a,b)
54
+ (a.class == b.class) or note_failure("Saw a #{a.class} but expected a #{b.class}\n")
55
+ end
56
+ def seen_either_before(a,b)
57
+ result = (has_key?(a.object_id) or has_key?(b.object_id))
58
+ (self[a.object_id] = self[b.object_id] = size) unless result or a.is_a? Numeric
59
+ result
60
+ end
61
+ def matched_before(a,b)
62
+ (self[a.object_id] == self[b.object_id]) or note_failure("#{a.inspect} [#{a.object_id}] and #{b.inspect} [#{b.object_id}] should refer to the same object.\n")
63
+ end
64
+ def same_object(a,b)
65
+ a.object_id == b.object_id
66
+ end
67
+
68
+ def guess_mapping(a,b)
69
+ result = {}
70
+ a.delete_if{|xa| result[xa] = b.delete(xa) }
71
+ raise "Too many odd keys in a test hash to tell if the results are correct." if a.length > 1
72
+ a.each {|xa| result[xa] = b.pop }
73
+ result
74
+ end
75
+ def same_properties(a,b)
76
+ @what_we_are_looking_at ||= []
77
+ return true if @what_we_are_looking_at.include? [a.object_id,b.object_id]
78
+ @what_we_are_looking_at.push [a.object_id,b.object_id]
79
+ result =
80
+ case a
81
+ when Array
82
+ (a.length == b.length) and a.zip(b).all?{|ia,ib| equivalent(ia,ib) }
83
+ when Hash
84
+ key_map = guess_mapping(a.keys,b.keys)
85
+ a.keys.length == b.keys.length and a.keys.all? {|a_k|
86
+ b_k = key_map[a_k]
87
+ equivalent(a_k,b_k) and equivalent(a[a_k],b[b_k])
88
+ }
89
+ when Exception
90
+ equivalent(a.message,b.message)
91
+ when Time,Date,Numeric,nil,true,false,Range,Symbol,String,Regexp
92
+ a == b
93
+ else
94
+ a.to_yaml_properties.all?{|p| equivalent(a.instance_variable_get(p),b.instance_variable_get(p)) }
95
+ end or note_failure("Expected:\n #{b.inspect}\n but got:\n #{a.inspect}\n")
96
+ @what_we_are_looking_at.pop
97
+ result
98
+ end
99
+ def equivalent(a,b)
100
+ if seen_either_before(a,b) then matched_before(a,b) else
101
+ (same_object(a,b) or (same_class(a,b) and same_properties(a,b))) ; end
102
+ end
103
+ end
104
+ def stripped(x)
105
+ x.gsub(/ +$/,'').chomp.chomp.gsub(/\n+/,"\n")
106
+ end
107
+ def dump_test(obj)
108
+ z_load = YAML.load(z_dump = ZAML.dump(obj)) rescue "ZAML produced something YAML can't load."
109
+ y_load = YAML.load(y_dump = YAML.dump(obj)) rescue "YAML failed to eat it's own dogfood"
110
+ context = {}
111
+ if ENCODING_KLUDGE && (RUBY_VERSION >= "1.9")
112
+ if obj.respond_to?(:encoding) && z_load.respond_to?(:force_encoding) then z_load.force_encoding(obj.encoding) ; end
113
+ end
114
+ test = Equivalency.test(z_load,obj)
115
+ assert_block("Reload discrepancy:\n#{test.message}\nZAML:\"\n#{z_dump}\"\nYAML:\"\n#{y_dump}\"\n\n") { test.result }
116
+ if Equivalency.test(y_load,obj).result and (not obj.is_a? String) and ($skip_text_compare != :skip)
117
+ assert_equal stripped(y_dump), stripped(z_dump), "Dump discrepancy"
118
+ end
119
+ end
120
+
121
+ #
122
+ # dump tests
123
+ #
124
+
125
+ def test_dump_object
126
+ dump_test(Object.new)
127
+ dump_test(My_class.new)
128
+ end
129
+
130
+ def test_dump_nil
131
+ dump_test(nil)
132
+ end
133
+ def test_dump_symbol
134
+ dump_test(:sym)
135
+ end
136
+ def test_dump_true
137
+ dump_test(true)
138
+ end
139
+ def test_dump_false
140
+ dump_test(false)
141
+ end
142
+ def test_dump_numeric
143
+ dump_test(1)
144
+ dump_test(1.1)
145
+ end
146
+ def test_dump_exception
147
+ dump_test(Exception.new('error message'))
148
+ dump_test(ArgumentError.new('error message'))
149
+ end
150
+ def test_dump_regexp
151
+ dump_test(/abc/)
152
+ dump_test(/a.*(b+)/im)
153
+ end
154
+ def test_dump_time
155
+ dump_test(Time.now)
156
+ end
157
+ def test_dump_date
158
+ dump_test(Date.strptime('2008-08-08'))
159
+ end
160
+ def test_dump_range
161
+ dump_test(1..10)
162
+ dump_test('a'...'b')
163
+ end
164
+
165
+ def test_dump_short_strings
166
+ #
167
+ every_character = (0..255).collect{|n| n.chr }
168
+ letters = 'a'..'z'
169
+ some_characters = (0..127).collect{|n| n.chr } - ('A'..'Z').to_a - ('b'..'z').to_a - ('1'..'9').to_a
170
+ fewer_characters = some_characters - every_character[1..31] + ["\n","\r","\t","\e"] - [127.chr,128.chr]
171
+ #
172
+ every_character.each{|c1| dump_test c1 }
173
+ every_character.each{|c1| dump_test "> "+c1 }
174
+ every_character.each_with_index{|c1,idx|
175
+ every_character.each{|c2| dump_test c1+c2 }
176
+ if idx % 16 == 0 then print ',' ; $stdout.flush ; end
177
+ } if SLOWNESS >= 1
178
+
179
+ letters.each{|c1|
180
+ letters.each{|c2|
181
+ print c1,c2,' ',8.chr*3
182
+ STDOUT.flush
183
+ letters.each{|c3|
184
+ dump_test c1+c2+c3
185
+ letters.each{|c4| dump_test c1+c2+c3+c4 }
186
+ }
187
+ }
188
+ GC.start
189
+ } if SLOWNESS >= 2 #slow
190
+ some_characters.each{|c1|
191
+ some_characters.each{|c2|
192
+ print((c1+c2).inspect,' ',8.chr*((c1+c2).inspect.length+8))
193
+ STDOUT.flush
194
+ some_characters.each{|c3|
195
+ some_characters.each{|c4| dump_test c1+c2+c3+c4 }
196
+ }
197
+ GC.start
198
+ }
199
+ } if SLOWNESS >= 3 #slower
200
+ fewer_characters.each{|c1|
201
+ fewer_characters.each{|c2|
202
+ print((c1+c2).inspect,' ',8.chr*((c1+c2).inspect.length+8))
203
+ STDOUT.flush
204
+ fewer_characters.each{|c3|
205
+ fewer_characters.each{|c4|
206
+ fewer_characters.each{|c5| dump_test c1+c2+c3+c4+c5 }
207
+ }
208
+ GC.start
209
+ }
210
+ }
211
+ } if SLOWNESS >= 4 #very slow
212
+ end
213
+
214
+ def test_system_dict_words
215
+ number_of_dict_words_to_test = 10**( SLOWNESS + 2 )
216
+ File.readlines(DICT_WORDS_PATH).take(number_of_dict_words_to_test).each{|w| dump_test w.chomp } if File.exists?(DICT_WORDS_PATH)
217
+ end
218
+
219
+ def test_dump_tricky_strings
220
+ dump_test("")
221
+ dump_test("#")
222
+ dump_test("!")
223
+ dump_test("~")
224
+ dump_test("=")
225
+ dump_test("\n")
226
+ dump_test("\n0")
227
+ dump_test("\n!")
228
+ dump_test("##")
229
+ dump_test("###")
230
+ dump_test("2:7")
231
+ dump_test("1:1 x")
232
+ dump_test(">")
233
+ dump_test(">>")
234
+ dump_test("> >")
235
+ dump_test("> !")
236
+ dump_test(">++ !")
237
+ dump_test(">0+ !")
238
+ dump_test("| |")
239
+ dump_test("0:0")
240
+ dump_test("1:2:3")
241
+ dump_test("+1:2:3")
242
+ dump_test("1:-2:+3")
243
+ dump_test("%.:.")
244
+ dump_test("%.:/")
245
+ dump_test("!\n")
246
+ dump_test("!\n\n")
247
+ dump_test("!\n\n\n\n ")
248
+ dump_test("!\n\n\n\n \n")
249
+ dump_test("!\n\n\n\n \n\n\n")
250
+ dump_test("!\n\n\n\n \n\n\r")
251
+ dump_test("!\n\n\n\n \n\n ")
252
+ dump_test("\n")
253
+ dump_test("\n\n")
254
+ dump_test("\n\n\n")
255
+ dump_test("\n\n\n\n ")
256
+ dump_test("\n\n\n\n \n")
257
+ dump_test(" ")
258
+ dump_test(" \r")
259
+ dump_test("\n\n\n\n \n\n\r")
260
+ dump_test("\n\n\n\n \n\n ")
261
+ end
262
+
263
+ def test_dump_string
264
+ dump_test('str')
265
+ dump_test(" leading and trailing whitespace ")
266
+ dump_test("a string \n with newline")
267
+ dump_test("a string with 'quotes'")
268
+ dump_test("a string with \"double quotes\"")
269
+ dump_test("a string with \\ escape")
270
+ dump_test("a really long string" * 10)
271
+ dump_test("a really long string \n with newline" * 10)
272
+ dump_test("a really long string with 'quotes'" * 10)
273
+ dump_test("a really long string with \"double quotes\"" * 10)
274
+ dump_test("a really long string with \\ escape" * 10)
275
+ dump_test("string with binary data \x00 \x01 \x02")
276
+ dump_test(" funky\n test\n")
277
+ dump_test('"')
278
+ dump_test("'")
279
+ dump_test('\\')
280
+ dump_test("k: v")
281
+ dump_test(":goo")
282
+ dump_test("? foo")
283
+ dump_test("{khkjh}")
284
+ dump_test("[ha]")
285
+ dump_test("- - (text) - -")
286
+ dump_test("\n\n \n \n x\n y\n z\n!\n")
287
+ end
288
+
289
+ def test_dump_strings_that_resemble_literals
290
+ dump_test("true")
291
+ dump_test("false")
292
+ dump_test("null")
293
+ dump_test("yes")
294
+ dump_test("no")
295
+ dump_test("on")
296
+ dump_test("off")
297
+ dump_test("nil")
298
+ dump_test("3")
299
+ dump_test("3.14")
300
+ dump_test("1e-6")
301
+ dump_test("0x345")
302
+ dump_test("-0x345")
303
+ dump_test("1e5")
304
+ end
305
+
306
+ STR = 'happy_str'
307
+
308
+ HASH = {
309
+ :nil => nil,
310
+ :sym => :value,
311
+ :true => true,
312
+ :false => false,
313
+ :int => 100,
314
+ :float => 1.1,
315
+ :regexp => /abc/,
316
+ STR => 'value',
317
+ :range => 1..10
318
+ }
319
+ ARRAY = [ nil, :sym, true, false, 100, 1.1, /abc/, STR, 1..10 ]
320
+
321
+ #
322
+ # hash
323
+ #
324
+
325
+ def test_dump_simple_hash
326
+ dump_test({:key => 'value'})
327
+ end
328
+ def test_dump_hash
329
+ dump_test(HASH)
330
+ end
331
+ def test_dump_simple_nested_hash
332
+ $skip_text_compare = :skip if INDENTED_ARRAYS_KLUDGE
333
+ dump_test({:hash => {:key => 'value'}, :array => [1,2,3]})
334
+ $skip_text_compare = false
335
+ end
336
+ def test_dump_nested_hash
337
+ $skip_text_compare = :skip if INDENTED_ARRAYS_KLUDGE
338
+ dump_test(HASH.merge(:hash => {:hash => {:key => 'value'}}, :array => [[1,2,3]]))
339
+ $skip_text_compare = false
340
+ end
341
+
342
+ # def test_dump_self_referential_hash
343
+ # array = ARRAY + [ARRAY]
344
+ # dump_test(HASH.merge(:hash => HASH, :array => array))
345
+ # end
346
+
347
+ def test_dump_self_referential_hash
348
+ if YAML_DUPS_STRINGS_KLUDGE
349
+ array = ARRAY.dup ; hsh = HASH.dup
350
+ array.delete(STR) ; hsh.delete(STR)
351
+ dump_test(hsh.merge(:hash => hsh, :array => (array + [ array ])))
352
+ else
353
+ array = ARRAY + [ARRAY]
354
+ dump_test(HASH.merge(:hash => HASH, :array => array))
355
+ end
356
+ end
357
+
358
+ def test_dump_singlular_self_referential_hash
359
+ hash = {}
360
+ hash[hash] = hash
361
+ dump_test(hash)
362
+ end
363
+ def test_dump_hash_value_with_colon
364
+ hash = { 'a' => 'a value:', 'b' => 'b value' }
365
+ dump_test(hash)
366
+ end
367
+
368
+ #
369
+ # array
370
+ #
371
+
372
+ def test_dump_simple_array
373
+ dump_test([1,2,3])
374
+ end
375
+ def test_dump_array
376
+ dump_test(ARRAY)
377
+ end
378
+ def test_dump_simple_nested_array
379
+ dump_test([{:key => 'value'}, [1,2,3]])
380
+ end
381
+ def test_dump_nested_array
382
+ $skip_text_compare = :skip if INDENTED_ARRAYS_KLUDGE
383
+ dump_test(ARRAY.concat([{:array => [1,2,3]}, [[1,2,3]]]))
384
+ $skil_text_compare = false
385
+ end
386
+
387
+ def test_dump_self_referential_array
388
+ if YAML_DUPS_STRINGS_KLUDGE
389
+ arr = ARRAY.dup ; hsh = HASH.dup
390
+ arr.delete(STR) ; hsh.delete(STR)
391
+ array = arr + [arr, hsh.merge(:hash => hsh)]
392
+ dump_test(array)
393
+ else
394
+ array = ARRAY + [ARRAY, HASH.merge(:hash => HASH)]
395
+ dump_test(array)
396
+ end
397
+ end
398
+
399
+ def test_dump_singlular_self_referential_array
400
+ array = []
401
+ array << array
402
+ dump_test(array)
403
+ end
404
+
405
+ #
406
+ # dump various data tests
407
+ #
408
+
409
+ my_range = 7..13
410
+ my_obj = My_class.new
411
+ my_dull_object = Object.new
412
+ my_bob = 'bob'
413
+ my_exception = Exception.new("Error message")
414
+ my_runtime_error = RuntimeError.new("This is a runtime error exception")
415
+ wright_joke = %q{
416
+
417
+ I was in the grocery store. I saw a sign that said "pet supplies".
418
+
419
+ So I did.
420
+
421
+ Then I went outside and saw a sign that said "compact cars".
422
+
423
+ -- Steven Wright
424
+ }
425
+ a_box_of_cheese = [:cheese]
426
+ DATA = [1, my_range, my_obj, my_bob, my_dull_object, 2, 'test', " funky\n test\n", true, false,
427
+ {my_obj => 'obj is the key!'},
428
+ {:bob => 6.8, :sam => 9.7, :subhash => {:sh1 => 'one', :sh2 => 'two'}},
429
+ 6, my_bob, my_obj, my_range, 'bob', 1..10, 0...8]
430
+ MORE_DATA = [{
431
+ :a_regexp => /a.*(b+)/im,
432
+ :an_exception => my_exception,
433
+ :a_runtime_error => my_runtime_error,
434
+ :a_long_string => wright_joke}
435
+ ]
436
+ NESTED_ARRAYS = [
437
+ [:one, 'One'],
438
+ [:two, 'Two'],
439
+ a_box_of_cheese,
440
+ [:three, 'Three'],
441
+ [:four, 'Four'],
442
+ a_box_of_cheese,
443
+ [:five, 'Five'],
444
+ [:six, 'Six']
445
+ ]
446
+ COMPLEX_DATA = {
447
+ :data => DATA,
448
+ :more_data => MORE_DATA,
449
+ :nested_arrays => NESTED_ARRAYS
450
+ }
451
+
452
+ def test_dump_DATA
453
+ dump_test(DATA)
454
+ end
455
+ def test_dump_MORE_DATA
456
+ dump_test(MORE_DATA)
457
+ end
458
+ def test_dump_NESTED_ARRAYS
459
+ dump_test(NESTED_ARRAYS)
460
+ end
461
+ def test_dump_COMPLEX_DATA
462
+ dump_test(COMPLEX_DATA)
463
+ end
464
+ def test_indentation_array_edge_cases
465
+ dump_test({[]=>[]})
466
+ dump_test([[]])
467
+ dump_test([[[],[]]])
468
+ end
469
+ def test_string_identity
470
+ a = 'str'
471
+ dump_test([a,a])
472
+ end
473
+ end