plist2 3.1.0

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.
@@ -0,0 +1,24 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>stringio</key>
6
+ <data>dGhpcyBpcyBhIHN0cmluZ2lvIG9iamVjdA==
7
+ </data>
8
+ <key>file</key>
9
+ <data>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
10
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
11
+ AAAAAAAAAAAAAA==
12
+ </data>
13
+ <key>io</key>
14
+ <data>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
15
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
16
+ AAAAAAAAAAAAAA==
17
+ </data>
18
+ <key>marshal</key>
19
+ <!-- The <data> element below contains a Ruby object which has been serialized with Marshal.dump. -->
20
+ <data>BAhvOhZNYXJzaGFsYWJsZU9iamVjdAY6CUBmb28iHnRoaXMgb2JqZWN0IHdh
21
+ cyBtYXJzaGFsZWQ=
22
+ </data>
23
+ </dict>
24
+ </plist>
@@ -0,0 +1,13 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>key</key>
6
+ <dict>
7
+ <key></key>
8
+ <string>1</string>
9
+ <key>subkey</key>
10
+ <string>2</string>
11
+ </dict>
12
+ </dict>
13
+ </plist>
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require 'plist'
5
+ require 'stringio'
6
+
7
+ class MarshalableObject
8
+ attr_accessor :foo
9
+
10
+ def initialize(str)
11
+ @foo = str
12
+ end
13
+ end
14
+
15
+ class TestDataElements < Test::Unit::TestCase
16
+
17
+ def setup
18
+ @result = Plist.parse_xml( 'test/assets/test_data_elements.plist' )
19
+ end
20
+
21
+ def test_data_object_header
22
+ expected = <<END
23
+ <!-- The <data> element below contains a Ruby object which has been serialized with Marshal.dump. -->
24
+ <data>
25
+ BAhvOhZNYXJzaGFsYWJsZU9iamVjdAY6CUBmb28iHnRoaXMgb2JqZWN0IHdhcyBtYXJz
26
+ aGFsZWQ=
27
+ </data>
28
+ END
29
+ expected_elements = expected.chomp.split( "\n" )
30
+
31
+ actual = Plist::Emit.dump( Object.new, false )
32
+ actual_elements = actual.chomp.split( "\n" )
33
+
34
+ # check for header
35
+ assert_equal expected_elements.shift, actual_elements.shift
36
+
37
+ # check for opening and closing data tags
38
+ assert_equal expected_elements.shift, actual_elements.shift
39
+ assert_equal expected_elements.pop, actual_elements.pop
40
+ end
41
+
42
+ def test_marshal_round_trip
43
+ expected = MarshalableObject.new('this object was marshaled')
44
+ actual = Plist.parse_xml( Plist::Emit.dump(expected, false) )
45
+
46
+ assert_kind_of expected.class, actual
47
+ assert_equal expected.foo, actual.foo
48
+ end
49
+
50
+ def test_generator_io_and_file
51
+ expected = <<END
52
+ <data>
53
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
54
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
55
+ </data>
56
+ END
57
+
58
+ expected.chomp!
59
+
60
+ fd = IO.sysopen('test/assets/example_data.bin')
61
+ io = IO.open(fd, 'r')
62
+
63
+ # File is a subclass of IO, so catching IO in the dispatcher should work for File as well...
64
+ f = File.open('test/assets/example_data.bin')
65
+
66
+ assert_equal expected, Plist::Emit.dump(io, false).chomp
67
+ assert_equal expected, Plist::Emit.dump(f, false).chomp
68
+
69
+ assert_instance_of StringIO, @result['io']
70
+ assert_instance_of StringIO, @result['file']
71
+
72
+ io.rewind
73
+ f.rewind
74
+
75
+ assert_equal io.read, @result['io'].read
76
+ assert_equal f.read, @result['file'].read
77
+
78
+ io.close
79
+ f.close
80
+ end
81
+
82
+ def test_generator_string_io
83
+ expected = <<END
84
+ <data>
85
+ dGhpcyBpcyBhIHN0cmluZ2lvIG9iamVjdA==
86
+ </data>
87
+ END
88
+
89
+ sio = StringIO.new('this is a stringio object')
90
+
91
+ assert_equal expected.chomp, Plist::Emit.dump(sio, false).chomp
92
+
93
+ assert_instance_of StringIO, @result['stringio']
94
+
95
+ sio.rewind
96
+ assert_equal sio.read, @result['stringio'].read
97
+ end
98
+
99
+ # this functionality is credited to Mat Schaffer,
100
+ # who discovered the plist with the data tag
101
+ # supplied the test data, and provided the parsing code.
102
+ def test_data
103
+ # test reading plist <data> elements
104
+ data = Plist::parse_xml("test/assets/example_data.plist");
105
+ assert_equal( File.open("test/assets/example_data.jpg"){|f| f.read }, data['image'].read )
106
+
107
+ # test writing data elements
108
+ expected = File.read("test/assets/example_data.plist")
109
+ result = data.to_plist
110
+ #File.open('result.plist', 'w') {|f|f.write(result)} # debug
111
+ assert_equal( expected, result )
112
+
113
+ # Test changing the <data> object in the plist to a StringIO and writing.
114
+ # This appears extraneous given that plist currently returns a StringIO,
115
+ # so the above writing test also flexes StringIO#to_plist_node.
116
+ # However, the interface promise is to return an IO, not a particular class.
117
+ # plist used to return Tempfiles, which was changed solely for performance reasons.
118
+ data['image'] = StringIO.new( File.read("test/assets/example_data.jpg"))
119
+
120
+ assert_equal(expected, data.to_plist )
121
+
122
+ end
123
+
124
+ end
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require 'plist'
5
+
6
+ class SerializableObject
7
+ attr_accessor :foo
8
+
9
+ def initialize(str)
10
+ @foo = str
11
+ end
12
+
13
+ def to_plist_node
14
+ return "<string>#{CGI::escapeHTML @foo}</string>"
15
+ end
16
+ end
17
+
18
+ class TestGenerator < Test::Unit::TestCase
19
+ def test_to_plist_vs_plist_emit_dump_no_envelope
20
+ source = [1, :b, true]
21
+
22
+ to_plist = source.to_plist(false)
23
+ plist_emit_dump = Plist::Emit.dump(source, false)
24
+
25
+ assert_equal to_plist, plist_emit_dump
26
+ end
27
+
28
+ def test_to_plist_vs_plist_emit_dump_with_envelope
29
+ source = [1, :b, true]
30
+
31
+ to_plist = source.to_plist
32
+ plist_emit_dump = Plist::Emit.dump(source)
33
+
34
+ assert_equal to_plist, plist_emit_dump
35
+ end
36
+
37
+ def test_dumping_serializable_object
38
+ str = 'this object implements #to_plist_node'
39
+ so = SerializableObject.new(str)
40
+
41
+ assert_equal "<string>#{str}</string>", Plist::Emit.dump(so, false)
42
+ end
43
+
44
+ def test_write_plist
45
+ data = [1, :two, {:c => 'dee'}]
46
+
47
+ data.save_plist('test.plist')
48
+ file = File.open('test.plist') {|f| f.read}
49
+
50
+ assert_equal file, data.to_plist
51
+
52
+ File.unlink('test.plist')
53
+ end
54
+
55
+ def spaces_to_tabs(s)
56
+ return s.gsub("\s\s", "\t")
57
+ end
58
+
59
+ # The hash in this test was failing with 'hsh.keys.sort',
60
+ # we are making sure it works with 'hsh.keys.sort_by'.
61
+ def test_sorting_keys
62
+ hsh = {:key1 => 1, :key4 => 4, 'key2' => 2, :key3 => 3}
63
+ expected = <<-STR
64
+ <dict>
65
+ <key>key1</key>
66
+ <integer>1</integer>
67
+ <key>key2</key>
68
+ <integer>2</integer>
69
+ <key>key3</key>
70
+ <integer>3</integer>
71
+ <key>key4</key>
72
+ <integer>4</integer>
73
+ </dict>
74
+ STR
75
+ expected = spaces_to_tabs(expected)
76
+ assert_equal expected, Plist::Emit.dump(hsh, false)
77
+ end
78
+
79
+ def test_hash_is_sorted
80
+ expected = <<END
81
+ <dict>
82
+ <key>a</key>
83
+ <string>a</string>
84
+ <key>b</key>
85
+ <string>b</string>
86
+ </dict>
87
+ END
88
+ h = Hash.new
89
+ h['b'] = 'b'
90
+ h['a'] = 'a'
91
+ expected = spaces_to_tabs(expected)
92
+ assert_equal expected, Plist::Emit.dump(h, false)
93
+ end
94
+
95
+ def test_hash_keeps_order_when_desired
96
+ expected = <<END
97
+ <dict>
98
+ <key>b</key>
99
+ <string>b</string>
100
+ <key>a</key>
101
+ <string>a</string>
102
+ </dict>
103
+ END
104
+ h = Hash.new
105
+ h['b'] = 'b'
106
+ h['a'] = 'a'
107
+ expected = spaces_to_tabs(expected)
108
+ assert_equal expected, Plist::Emit.dump(h, false, :sort => false)
109
+ end
110
+ end
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require 'plist'
5
+
6
+ class TestGeneratorBasicTypes < Test::Unit::TestCase
7
+ def wrap(tag, content)
8
+ return "<#{tag}>#{content}</#{tag}>"
9
+ end
10
+
11
+ def test_strings
12
+ expected = wrap('string', 'testdata')
13
+
14
+ assert_equal expected, Plist::Emit.dump('testdata', false).chomp
15
+ assert_equal expected, Plist::Emit.dump(:testdata, false).chomp
16
+ end
17
+
18
+ def test_strings_with_escaping
19
+ expected = wrap('string', "&lt;Fish &amp; Chips&gt;")
20
+
21
+ assert_equal expected, Plist::Emit.dump('<Fish & Chips>', false).chomp
22
+ end
23
+
24
+ def test_integers
25
+ [42, 2376239847623987623, -8192].each do |i|
26
+ assert_equal wrap('integer', i), Plist::Emit.dump(i, false).chomp
27
+ end
28
+ end
29
+
30
+ def test_floats
31
+ [3.14159, -38.3897, 2398476293847.9823749872349980].each do |i|
32
+ assert_equal wrap('real', i), Plist::Emit.dump(i, false).chomp
33
+ end
34
+ end
35
+
36
+ def test_booleans
37
+ assert_equal "<true/>", Plist::Emit.dump(true, false).chomp
38
+ assert_equal "<false/>", Plist::Emit.dump(false, false).chomp
39
+ end
40
+
41
+ def test_time
42
+ test_time = Time.now
43
+ assert_equal wrap('date', test_time.utc.strftime('%Y-%m-%dT%H:%M:%SZ')), Plist::Emit.dump(test_time, false).chomp
44
+ end
45
+
46
+ def test_dates
47
+ test_date = Date.today
48
+ test_datetime = DateTime.now
49
+
50
+ assert_equal wrap('date', test_date.strftime('%Y-%m-%dT%H:%M:%SZ')), Plist::Emit.dump(test_date, false).chomp
51
+ assert_equal wrap('date', test_datetime.strftime('%Y-%m-%dT%H:%M:%SZ')), Plist::Emit.dump(test_datetime, false).chomp
52
+ end
53
+ end
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require 'plist'
5
+
6
+ class TestGeneratorCollections < Test::Unit::TestCase
7
+ def test_array
8
+ expected = <<END
9
+ <array>
10
+ <integer>1</integer>
11
+ <integer>2</integer>
12
+ <integer>3</integer>
13
+ </array>
14
+ END
15
+
16
+ assert_equal expected, [1,2,3].to_plist(false)
17
+ end
18
+
19
+ def test_empty_array
20
+ expected = <<END
21
+ <array/>
22
+ END
23
+
24
+ assert_equal expected, [].to_plist(false)
25
+ end
26
+
27
+ def test_hash
28
+ expected = <<END
29
+ <dict>
30
+ <key>abc</key>
31
+ <integer>123</integer>
32
+ <key>foo</key>
33
+ <string>bar</string>
34
+ </dict>
35
+ END
36
+ # thanks to recent changes in the generator code, hash keys are sorted before emission,
37
+ # so multi-element hash tests should be reliable. We're testing that here too.
38
+ assert_equal expected, {:foo => :bar, :abc => 123}.to_plist(false)
39
+ end
40
+
41
+ def test_empty_hash
42
+ expected = <<END
43
+ <dict/>
44
+ END
45
+
46
+ assert_equal expected, {}.to_plist(false)
47
+ end
48
+
49
+ def test_hash_with_array_element
50
+ expected = <<END
51
+ <dict>
52
+ <key>ary</key>
53
+ <array>
54
+ <integer>1</integer>
55
+ <string>b</string>
56
+ <string>3</string>
57
+ </array>
58
+ </dict>
59
+ END
60
+ assert_equal expected, {:ary => [1,:b,'3']}.to_plist(false)
61
+ end
62
+
63
+ def test_array_with_hash_element
64
+ expected = <<END
65
+ <array>
66
+ <dict>
67
+ <key>foo</key>
68
+ <string>bar</string>
69
+ </dict>
70
+ <string>b</string>
71
+ <integer>3</integer>
72
+ </array>
73
+ END
74
+
75
+ assert_equal expected, [{:foo => 'bar'}, :b, 3].to_plist(false)
76
+ end
77
+ end
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require 'plist'
5
+
6
+ class TestParser < Test::Unit::TestCase
7
+ def test_Plist_parse_xml
8
+ result = Plist::parse_xml("test/assets/AlbumData.xml")
9
+
10
+ # dict
11
+ assert_kind_of( Hash, result )
12
+
13
+ expected = [
14
+ "List of Albums",
15
+ "Minor Version",
16
+ "Master Image List",
17
+ "Major Version",
18
+ "List of Keywords",
19
+ "Archive Path",
20
+ "List of Rolls",
21
+ "Application Version"
22
+ ]
23
+ assert_equal( expected.sort, result.keys.sort )
24
+
25
+ # array
26
+ assert_kind_of( Array, result["List of Rolls"] )
27
+ assert_equal( [ {"PhotoCount"=>1,
28
+ "KeyList"=>["7"],
29
+ "Parent"=>999000,
30
+ "Album Type"=>"Regular",
31
+ "AlbumName"=>"Roll 1",
32
+ "AlbumId"=>6}],
33
+ result["List of Rolls"] )
34
+
35
+ # string
36
+ assert_kind_of( String, result["Application Version"] )
37
+ assert_equal( "5.0.4 (263)", result["Application Version"] )
38
+
39
+ # integer
40
+ assert_kind_of( Integer, result["Major Version"] )
41
+ assert_equal( 2, result["Major Version"] )
42
+
43
+ # true
44
+ assert_kind_of( TrueClass, result["List of Albums"][0]["Master"] )
45
+ assert( result["List of Albums"][0]["Master"] )
46
+
47
+ # false
48
+ assert_kind_of( FalseClass, result["List of Albums"][1]["SlideShowUseTitles"] )
49
+ assert( ! result["List of Albums"][1]["SlideShowUseTitles"] )
50
+
51
+ end
52
+
53
+ # uncomment this test to work on speed optimization
54
+ #def test_load_something_big
55
+ # plist = Plist::parse_xml( "~/Pictures/iPhoto Library/AlbumData.xml" )
56
+ #end
57
+
58
+ # date fields are credited to
59
+ def test_date_fields
60
+ result = Plist::parse_xml("test/assets/Cookies.plist")
61
+ assert_kind_of( DateTime, result.first['Expires'] )
62
+ assert_equal DateTime.parse( "2007-10-25T12:36:35Z" ), result.first['Expires']
63
+ end
64
+
65
+ # bug fix for empty <key>
66
+ # reported by Matthias Peick <matthias@peick.de>
67
+ # reported and fixed by Frederik Seiffert <ego@frederikseiffert.de>
68
+ def test_empty_dict_key
69
+ data = Plist::parse_xml("test/assets/test_empty_key.plist");
70
+ assert_equal("2", data['key']['subkey'])
71
+ end
72
+
73
+ # bug fix for decoding entities
74
+ # reported by Matthias Peick <matthias@peick.de>
75
+ def test_decode_entities
76
+ data = Plist::parse_xml('<string>Fish &amp; Chips</string>')
77
+ assert_equal('Fish & Chips', data)
78
+ end
79
+
80
+ def test_comment_handling_and_empty_plist
81
+ assert_nothing_raised do
82
+ assert_nil( Plist::parse_xml( File.read('test/assets/commented.plist') ) )
83
+ end
84
+ end
85
+
86
+ def test_filename_or_xml_is_stringio
87
+ require 'stringio'
88
+
89
+ str = StringIO.new
90
+ data = Plist::parse_xml(str)
91
+
92
+ assert_nil data
93
+ end
94
+
95
+ end
96
+
97
+ __END__