|
From: Grant M. <gr...@us...> - 2003-04-10 10:20:16
|
Update of /cvsroot/perl-xml/xml-simple/t
In directory sc8-pr-cvs1:/tmp/cvs-serv18853
Modified Files:
1_XMLin.t 2_XMLout.t 3_Storable.t 6_ObjIntf.t 9_Strict.t
Log Message:
- tests for new features in release 2.04
Index: 1_XMLin.t
===================================================================
RCS file: /cvsroot/perl-xml/xml-simple/t/1_XMLin.t,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- 1_XMLin.t 20 Jan 2003 07:48:59 -0000 1.10
+++ 1_XMLin.t 10 Apr 2003 10:20:06 -0000 1.11
@@ -15,14 +15,14 @@
plan skip_all => 'Test data missing';
}
-plan tests => 66;
+plan tests => 93;
$@ = '';
eval "use XML::Simple;";
is($@, '', 'Module compiled OK');
-unless($XML::Simple::VERSION eq '2.03') {
- diag("Warning: XML::Simple::VERSION = $XML::Simple::VERSION (expected 2.03)");
+unless($XML::Simple::VERSION eq '2.04') {
+ diag("Warning: XML::Simple::VERSION = $XML::Simple::VERSION (expected 2.04)");
}
@@ -134,13 +134,14 @@
{name => 'item2', attr1 => 'value3', attr2 => 'value4' }
]
};
-$opt = XMLin($string, keyattr => [] );
+my @cont_key = (contentkey => '-content');
+$opt = XMLin($string, keyattr => [], @cont_key);
is_deeply($opt, $target, 'not folded when keyattr turned off');
# Same again with alternative key suppression
-$opt = XMLin($string, keyattr => {} );
+$opt = XMLin($string, keyattr => {}, @cont_key);
is_deeply($opt, $target, 'still works when keyattr is empty hash');
@@ -151,7 +152,7 @@
<item key="item1" attr1="value1" attr2="value2" />
<item key="item2" attr1="value3" attr2="value4" />
</opt>
-));
+), @cont_key);
is_deeply($opt, {
item => {
item1 => { attr1 => 'value1', attr2 => 'value2' },
@@ -165,7 +166,7 @@
<item id="item1" attr1="value1" attr2="value2" />
<item id="item2" attr1="value3" attr2="value4" />
</opt>
-));
+), @cont_key);
is_deeply($opt, {
item => {
item1 => { attr1 => 'value1', attr2 => 'value2' },
@@ -189,28 +190,40 @@
}
};
-$opt = XMLin($xml, keyattr => [qw(xname)]);
+$opt = XMLin($xml, keyattr => [qw(xname)], @cont_key);
is_deeply($opt, $target, "folded on non-default key 'xname'");
# And with precise element/key specification
-$opt = XMLin($xml, keyattr => { 'item' => 'xname' });
+$opt = XMLin($xml, keyattr => { 'item' => 'xname' }, @cont_key);
is_deeply($opt, $target, 'same again but keyattr set with hash');
# Same again but with key field further down the list
-$opt = XMLin($xml, keyattr => [qw(wibble xname)]);
+$opt = XMLin($xml, keyattr => [qw(wibble xname)], @cont_key);
is_deeply($opt, $target, 'keyattr as array with value in second position');
# Same again but with key field supplied as scalar
-$opt = XMLin($xml, keyattr => qw(xname));
+$opt = XMLin($xml, keyattr => qw(xname), @cont_key);
is_deeply($opt, $target, 'keyattr as scalar');
+# Same again but with mixed-case option name
+
+$opt = XMLin($xml, KeyAttr => qw(xname), @cont_key);
+is_deeply($opt, $target, 'KeyAttr as scalar');
+
+
+# Same again but with underscores in option name
+
+$opt = XMLin($xml, key_attr => qw(xname), @cont_key);
+is_deeply($opt, $target, 'key_attr as scalar');
+
+
# Weird variation, not exactly what we wanted but it is what we expected
# given the current implementation and we don't want to break it accidently
@@ -229,7 +242,7 @@
}
};
-$opt = XMLin($xml);
+$opt = XMLin($xml, @cont_key);
is_deeply($opt, $target, 'fold same array on two different keys');
@@ -241,7 +254,7 @@
'three' => { 'value' => '3' },
}
};
-$opt = XMLin($xml, keyattr => { 'item' => 'id' });
+$opt = XMLin($xml, keyattr => { 'item' => 'id' }, @cont_key);
is_deeply($opt, $target, 'same again but with priority switch');
@@ -281,7 +294,8 @@
}
};
-$opt = XMLin($xml, forcearray => 1, keyattr => { 'car' => 'license', 'option' => 'pn' });
+$opt = XMLin($xml, forcearray => 1,
+ keyattr => { 'car' => 'license', 'option' => 'pn' }, @cont_key);
is_deeply($opt, $target, 'folded on multi-key keyattr hash');
@@ -313,7 +327,7 @@
}
}
};
-$opt = XMLin($xml, forcearray => 1, keyattr => { 'car' => '+license', 'option' => '-pn' });
+$opt = XMLin($xml, forcearray => 1, keyattr => { 'car' => '+license', 'option' => '-pn' }, @cont_key);
is_deeply($opt, $target, "same again but with '+' prefix to copy keys");
@@ -338,20 +352,22 @@
]
};
-$opt = XMLin($xml);
+$opt = XMLin($xml, @cont_key);
is_deeply($opt, $target, "did not fold on default key with non-scalar value");
-$opt = XMLin($xml, keyattr => { item => 'name' });
+$opt = XMLin($xml, keyattr => { item => 'name' }, @cont_key);
is_deeply($opt, $target, "did not fold on specific key with non-scalar value");
# Make sure that the root element name is preserved if we ask for it
$target = XMLin("<opt>$xml</opt>", forcearray => 1,
- keyattr => { 'car' => '+license', 'option' => '-pn' });
+ keyattr => { 'car' => '+license', 'option' => '-pn' },
+ @cont_key);
$opt = XMLin( $xml, forcearray => 1, keeproot => 1,
- keyattr => { 'car' => '+license', 'option' => '-pn' });
+ keyattr => { 'car' => '+license', 'option' => '-pn' },
+ @cont_key);
is_deeply($opt, $target, 'keeproot option works');
@@ -359,13 +375,13 @@
# confirm that CDATA sections parse correctly
$xml = q{<opt><cdata><![CDATA[<greeting>Hello, world!</greeting>]]></cdata></opt>};
-$opt = XMLin($xml);
+$opt = XMLin($xml, @cont_key);
is_deeply($opt, {
'cdata' => '<greeting>Hello, world!</greeting>'
}, 'CDATA section parsed correctly');
$xml = q{<opt><x><![CDATA[<y>one</y>]]><![CDATA[<y>two</y>]]></x></opt>};
-$opt = XMLin($xml);
+$opt = XMLin($xml, @cont_key);
is_deeply($opt, {
'x' => '<y>one</y><y>two</y>'
}, 'CDATA section containing markup characters parsed correctly');
@@ -396,7 +412,7 @@
$@ = '';
$opt = eval {
XMLin('test2.xml', searchpath => [
- 'dir1', 'dir2', File::Spec->catdir('t', 'subdir')
+ 'dir1', 'dir2', File::Spec->catdir('t', 'subdir'), @cont_key
] );
};
@@ -424,7 +440,7 @@
$XMLFile = File::Spec->catfile('t', '1_XMLin.xml'); # t/1_XMLin.xml
eval {
$fh->open($XMLFile) || die "$!";
- $opt = XMLin($fh);
+ $opt = XMLin($fh, @cont_key);
};
is($@, '', "XMLin didn't choke on an IO::File object");
is($opt->{location}, 't/1_XMLin.xml', 'and it parsed the right file');
@@ -456,7 +472,7 @@
<anon>2.0</anon><anon>2.1</anon><anon>2.2</anon>
</row>
</opt>
-));
+), @cont_key);
is_deeply($opt, {
row => [
[ '0.0', '0.1', '0.2' ],
@@ -474,7 +490,7 @@
<anon>two</anon>
<anon>three</anon>
</opt>
-});
+}, @cont_key);
is_deeply($opt, [
qw(one two three)
], 'top level anonymous array returned arrayref');
@@ -491,7 +507,7 @@
</anon>
</anon>
</opt>
-));
+), @cont_key);
is_deeply($opt, [
1,
[
@@ -558,11 +574,37 @@
}, "even when we change it's name to 'text'");
+# Confirm that spurious 'content' keys are *not* eliminated after array folding
+
+$xml = q(<opt><x y="one">First</x><x y="two">Second</x></opt>);
+$opt = XMLin($xml, forcearray => [ 'x' ], keyattr => {x => 'y'});
+is_deeply($opt, {
+ x => {
+ one => { content => 'First' },
+ two => { content => 'Second' },
+ }
+}, "spurious content keys not eliminated after folding");
+
+
+# unless we ask nicely
+
+$xml = q(<opt><x y="one">First</x><x y="two">Second</x></opt>);
+$opt = XMLin(
+ $xml, forcearray => [ 'x' ], keyattr => {x => 'y'}, contentkey => '-content'
+);
+is_deeply($opt, {
+ x => {
+ one => 'First',
+ two => 'Second',
+ }
+}, "spurious content keys not eliminated after folding");
+
+
# Check that mixed content parses in the weird way we expect
$xml = q(<p class="mixed">Text with a <b>bold</b> word</p>);
-is_deeply(XMLin($xml), {
+is_deeply(XMLin($xml, @cont_key), {
'class' => 'mixed',
'content' => [ 'Text with a ', ' word' ],
'b' => 'bold'
@@ -584,7 +626,7 @@
# Unless 'forcearray' option is specified
-$opt = XMLin($string, forcearray => 1);
+$opt = XMLin($string, forcearray => 1, @cont_key);
is_deeply($opt, {
name => [ 'value' ]
}, 'except when forcearray is enabled');
@@ -596,7 +638,7 @@
<inner name="one" value="1" />
</opt>);
-$opt = XMLin($string, forcearray => 1);
+$opt = XMLin($string, forcearray => 1, @cont_key);
is_deeply($opt, {
'inner' => { 'one' => { 'value' => 1 } }
}, 'array folding works with single nested hash');
@@ -604,7 +646,7 @@
# But not without forcearray option specified
-$opt = XMLin($string, forcearray => 0);
+$opt = XMLin($string, forcearray => 0, @cont_key);
is_deeply($opt, {
'inner' => { 'name' => 'one', 'value' => 1 }
}, 'but not if forcearray is turned off');
@@ -621,7 +663,7 @@
</opt>
);
-$opt = XMLin($xml, forcearray => [ 'two' ]);
+$opt = XMLin($xml, forcearray => [ 'two' ], @cont_key);
is_deeply($opt, {
'zero' => '0',
'one' => 'i',
@@ -637,7 +679,7 @@
</opt>
);
-$opt = XMLin($xml, noattr => 1);
+$opt = XMLin($xml, noattr => 1, @cont_key);
is_deeply($opt, { nest => 'text' }, 'attributes successfully skipped');
@@ -651,7 +693,7 @@
};
-$opt = XMLin($xml, noattr => 1);
+$opt = XMLin($xml, noattr => 1, @cont_key);
is_deeply($opt, {
'item' => {
'a' => { 'value' => 'alpha' },
@@ -671,7 +713,7 @@
</outer>
</body>);
-$opt = XMLin($xml, noattr => 1);
+$opt = XMLin($xml, noattr => 1, @cont_key);
is_deeply($opt, {
'name' => 'bob',
'outer' => {
@@ -683,13 +725,13 @@
# Unless 'suppressempty' is enabled
-$opt = XMLin($xml, noattr => 1, suppressempty => 1);
+$opt = XMLin($xml, noattr => 1, suppressempty => 1, @cont_key);
is_deeply($opt, { 'name' => 'bob', }, 'or are suppressed');
# Check behaviour when 'suppressempty' is set to to undef;
-$opt = XMLin($xml, noattr => 1, suppressempty => undef);
+$opt = XMLin($xml, noattr => 1, suppressempty => undef, @cont_key);
is_deeply($opt, {
'name' => 'bob',
'outer' => {
@@ -700,7 +742,7 @@
# Check behaviour when 'suppressempty' is set to to empty string;
-$opt = XMLin($xml, noattr => 1, suppressempty => '');
+$opt = XMLin($xml, noattr => 1, suppressempty => '', @cont_key);
is_deeply($opt, {
'name' => 'bob',
'outer' => {
@@ -718,10 +760,274 @@
</outer>
</body>);
-$opt = XMLin($xml, noattr => 1, suppressempty => 1);
+$opt = XMLin($xml, noattr => 1, suppressempty => 1, @cont_key);
is($opt, undef, 'empty document parses to undef');
+# Confirm nothing magical happens with grouped elements
+
+$xml = q(<opt>
+ <prefix>before</prefix>
+ <dirs>
+ <dir>/usr/bin</dir>
+ <dir>/usr/local/bin</dir>
+ </dirs>
+ <suffix>after</suffix>
+</opt>);
+
+$opt = XMLin($xml);
+is_deeply($opt, {
+ prefix => 'before',
+ dirs => {
+ dir => [ '/usr/bin', '/usr/local/bin' ]
+ },
+ suffix => 'after',
+}, 'grouped tags parse normally');
+
+
+# unless we specify how the grouping works
+
+$xml = q(<opt>
+ <prefix>before</prefix>
+ <dirs>
+ <dir>/usr/bin</dir>
+ <dir>/usr/local/bin</dir>
+ </dirs>
+ <suffix>after</suffix>
+</opt>);
+
+$opt = XMLin($xml, grouptags => {dirs => 'dir'} );
+is_deeply($opt, {
+ prefix => 'before',
+ dirs => [ '/usr/bin', '/usr/local/bin' ],
+ suffix => 'after',
+}, 'disintermediation of grouped tags works');
+
+
+# try again with multiple groupings
+
+$xml = q(<opt>
+ <prefix>before</prefix>
+ <dirs>
+ <dir>/usr/bin</dir>
+ <dir>/usr/local/bin</dir>
+ </dirs>
+ <infix>between</infix>
+ <terms>
+ <term>vt100</term>
+ <term>xterm</term>
+ </terms>
+ <suffix>after</suffix>
+</opt>);
+
+$opt = XMLin($xml, grouptags => {dirs => 'dir', terms => 'term'} );
+is_deeply($opt, {
+ prefix => 'before',
+ dirs => [ '/usr/bin', '/usr/local/bin' ],
+ infix => 'between',
+ terms => [ 'vt100', 'xterm' ],
+ suffix => 'after',
+}, 'disintermediation works with multiple groups');
+
+
+# confirm folding and ungrouping work together
+
+$xml = q(<opt>
+ <prefix>before</prefix>
+ <dirs>
+ <dir name="first">/usr/bin</dir>
+ <dir name="second">/usr/local/bin</dir>
+ </dirs>
+ <suffix>after</suffix>
+</opt>);
+
+$opt = XMLin($xml, keyattr => {dir => 'name'}, grouptags => {dirs => 'dir'} );
+is_deeply($opt, {
+ prefix => 'before',
+ dirs => {
+ first => { content => '/usr/bin' },
+ second => { content => '/usr/local/bin' },
+ },
+ suffix => 'after',
+}, 'folding and ungrouping work together');
+
+
+# confirm folding, ungrouping and content stripping work together
+
+$xml = q(<opt>
+ <prefix>before</prefix>
+ <dirs>
+ <dir name="first">/usr/bin</dir>
+ <dir name="second">/usr/local/bin</dir>
+ </dirs>
+ <suffix>after</suffix>
+</opt>);
+
+$opt = XMLin($xml,
+ contentkey => '-text',
+ keyattr => {dir => 'name'},
+ grouptags => {dirs => 'dir'}
+);
+is_deeply($opt, {
+ prefix => 'before',
+ dirs => {
+ first => '/usr/bin',
+ second => '/usr/local/bin',
+ },
+ suffix => 'after',
+}, 'folding, ungrouping and content stripping work together');
+
+
+# confirm folding fails as expected even with ungrouping but (no forcearray)
+
+$xml = q(<opt>
+ <prefix>before</prefix>
+ <dirs>
+ <dir name="first">/usr/bin</dir>
+ </dirs>
+ <suffix>after</suffix>
+</opt>);
+
+$opt = XMLin($xml,
+ contentkey => '-text',
+ keyattr => {dir => 'name'},
+ grouptags => {dirs => 'dir'}
+);
+is_deeply($opt, {
+ prefix => 'before',
+ dirs => { name => 'first', text => '/usr/bin'},
+ suffix => 'after',
+}, 'folding without forcearray but with ungrouping fails as expected');
+
+
+# but works with forcearray enabled
+
+$xml = q(<opt>
+ <prefix>before</prefix>
+ <dirs>
+ <dir name="first">/usr/bin</dir>
+ </dirs>
+ <suffix>after</suffix>
+</opt>);
+
+$opt = XMLin($xml,
+ contentkey => '-text',
+ forcearray => [ 'dir' ],
+ keyattr => {dir => 'name'},
+ grouptags => {dirs => 'dir'}
+);
+is_deeply($opt, {
+ prefix => 'before',
+ dirs => {'first' => '/usr/bin'},
+ suffix => 'after',
+}, 'folding with forcearray and ungrouping works');
+
+
+# Test variable expansion - when no variables are defined
+
+$xml = q(<opt>
+ <file name="config_file">${conf_dir}/appname.conf</file>
+ <file name="log_file">${log_dir}/appname.log</file>
+ <file name="debug_file">${log_dir}/appname.dbg</file>
+</opt>);
+
+$opt = XMLin($xml, contentkey => '-content');
+is_deeply($opt, {
+ file => {
+ config_file => '${conf_dir}/appname.conf',
+ log_file => '${log_dir}/appname.log',
+ debug_file => '${log_dir}/appname.dbg',
+ }
+}, 'undefined variables are left untouched');
+
+
+# try again but with variables defined in advance
+
+$opt = XMLin($xml,
+ contentkey => '-content',
+ variables => { conf_dir => '/etc', log_dir => '/var/log' }
+);
+is_deeply($opt, {
+ file => {
+ config_file => '/etc/appname.conf',
+ log_file => '/var/log/appname.log',
+ debug_file => '/var/log/appname.dbg',
+ }
+}, 'substitution of pre-defined variables works');
+
+
+# now try defining them in the XML
+
+$xml = q(<opt>
+ <dir xsvar="conf_dir">/etc</dir>
+ <dir xsvar="log_dir">/var/log</dir>
+ <file name="config_file">${conf_dir}/appname.conf</file>
+ <file name="log_file">${log_dir}/appname.log</file>
+ <file name="debug_file">${log_dir}/appname.dbg</file>
+</opt>);
+
+$opt = XMLin($xml, contentkey => '-content', varattr => 'xsvar');
+is_deeply($opt, {
+ file => {
+ config_file => '/etc/appname.conf',
+ log_file => '/var/log/appname.log',
+ debug_file => '/var/log/appname.dbg',
+ },
+ dir => [
+ { xsvar => 'conf_dir', content => '/etc' },
+ { xsvar => 'log_dir', content => '/var/log' },
+ ]
+}, 'variables defined in XML work');
+
+
+# confirm that variables in XML are merged with pre-defined ones
+
+$xml = q(<opt>
+ <dir xsvar="log_dir">/var/log</dir>
+ <file name="config_file">${conf_dir}/appname.conf</file>
+ <file name="log_file">${log_dir}/appname.log</file>
+ <file name="debug_file">${log_dir}/appname.dbg</file>
+</opt>);
+
+$opt = XMLin($xml,
+ contentkey => '-content',
+ varattr => 'xsvar',
+ variables => { conf_dir => '/etc', log_dir => '/tmp' }
+);
+is_deeply($opt, {
+ file => {
+ config_file => '/etc/appname.conf',
+ log_file => '/var/log/appname.log',
+ debug_file => '/var/log/appname.dbg',
+ },
+ dir => { xsvar => 'log_dir', content => '/var/log' },
+}, 'variables defined in XML merged successfully with predefined vars');
+
+
+# confirm that a variables are expanded in variable definitions
+
+$xml = q(<opt>
+ <dirs>
+ <dir name="prefix">/usr/local/apache</dir>
+ <dir name="exec_prefix">${prefix}</dir>
+ <dir name="bin_dir">${exec_prefix}/bin</dir>
+ </dirs>
+</opt>);
+
+$opt = XMLin($xml,
+ contentkey => '-content',
+ varattr => 'name',
+ grouptags => { dirs => 'dir' },
+);
+is_deeply($opt, {
+ dirs => {
+ prefix => '/usr/local/apache',
+ exec_prefix => '/usr/local/apache',
+ bin_dir => '/usr/local/apache/bin',
+ }
+}, 'variables are expanded in later variable definitions');
+
+
# Test option error handling
$@='';
@@ -736,9 +1042,59 @@
'with correct error message');
+# Test the NormaliseSpace option
+
+$xml = q(<opt>
+ <user name=" Joe
+ Bloggs " id=" one two "/>
+ <user>
+ <name> Jane
+ Doe </name>
+ <id>
+ three
+ four
+ </id>
+ </user>
+</opt>);
+
+$opt = XMLin($xml, KeyAttr => [ 'name' ], NormaliseSpace => 1);
+ok(ref($opt->{user}) eq 'HASH', "NS-1: folding OK");
+ok(exists($opt->{user}->{'Joe Bloggs'}), "NS-2: space normalised in hash key");
+ok(exists($opt->{user}->{'Jane Doe'}), "NS-3: space normalised in hash key");
+like($opt->{user}->{'Jane Doe'}->{id}, qr{^\s\s+three\s\s+four\s\s+$}s,
+ "NS-4: space not normalised in hash value");
+
+$opt = XMLin($xml, KeyAttr => [ 'name' ], NormaliseSpace => 2);
+ok(ref($opt->{user}) eq 'HASH', "NS-5: folding OK");
+ok(exists($opt->{user}->{'Joe Bloggs'}), "NS-6: space normalised in hash key");
+like($opt->{user}->{'Joe Bloggs'}->{id}, qr{^one\stwo$}s,
+ "NS-7: space normalised in attribute value");
+ok(exists($opt->{user}->{'Jane Doe'}), "NS-8: space normalised in hash key");
+like($opt->{user}->{'Jane Doe'}->{id}, qr{^three\sfour$}s,
+ "NS-9: space normalised in element text content");
+
+# confirm NormaliseSpace works in anonymous arrays too
+
+$xml = q(<opt>
+ <anon> one two </anon><anon> three
+ four five </anon><anon> six </anon><anon> seveneightnine </anon>
+</opt>);
+
+$opt = XMLin($xml, NormaliseSpace => 2);
+is_deeply($opt, [ 'one two', 'three four five', 'six', 'seveneightnine' ],
+ "NS-10: space normalised in anonymous array");
+
+# Check that American speeling works too
+
+$opt = XMLin($xml, NormalizeSpace => 2);
+is_deeply($opt, [ 'one two', 'three four five', 'six', 'seveneightnine' ],
+ "NS-11: space normalized in anonymous array");
+
# Now for a 'real world' test, try slurping in an SRT config file
-$opt = XMLin(File::Spec->catfile('t', 'srt.xml'), forcearray => 1);
+$opt = XMLin(File::Spec->catfile('t', 'srt.xml'),
+ forcearray => 1, @cont_key
+);
$target = {
'global' => [
{
Index: 2_XMLout.t
===================================================================
RCS file: /cvsroot/perl-xml/xml-simple/t/2_XMLout.t,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- 2_XMLout.t 20 Jan 2003 07:48:10 -0000 1.5
+++ 2_XMLout.t 10 Apr 2003 10:20:07 -0000 1.6
@@ -5,7 +5,7 @@
use Test::More;
use IO::File;
-plan tests => 174;
+plan tests => 190;
##############################################################################
# S U P P O R T R O U T I N E S
@@ -681,6 +681,13 @@
like($_, qr{^\s*<opt\s+one="1">text</opt>\s*$}s, 'even when name changed');
+# and also if we add the '-' prefix
+
+$_ = XMLout($ref, contentkey => '-text_content');
+
+like($_, qr{^\s*<opt\s+one="1">text</opt>\s*$}s, 'even with "-" prefix');
+
+
# Check 'noattr' option
$ref = {
@@ -748,6 +755,129 @@
ok(s{\s*<(word)>thirty two</\1>\s*}{32}s, 'scalar 2.1 mapped OK');
ok(s{\s*<(number)>323232</\1>\s*}{NUM}s, 'element 2 OK');
like($_, qr{^<(\w+)\s*>NUMNUM</\1>$}, 'document OK');
+
+
+# Check grouped tags get ungrouped correctly
+
+$ref = {
+ prefix => 'before',
+ dirs => [ '/usr/bin', '/usr/local/bin' ],
+ suffix => 'after',
+};
+
+# Expect:
+#
+# <opt>
+# <prefix>before</prefix>
+# <dirs>
+# <dir>/usr/bin</dir>
+# <dir>/usr/local/bin</dir>
+# </dirs>
+# <suffix>after</suffix>
+# </opt>
+#
+
+$_ = XMLout($ref, grouptags => {dirs => 'dir'}, noattr => 1);
+
+ok(s{\s*<(prefix)>before</\1>\s*}{ELEM}s, 'prefix OK');
+ok(s{\s*<(suffix)>after</\1>\s*}{ELEM}s, 'suffix OK');
+ok(s{\s*<dir>/usr/bin</dir>\s*<dir>/usr/local/bin</dir>\s*}{LIST}s, 'list OK');
+ok(s{\s*<dirs>LIST</dirs>\s*}{ELEM}s, 'group OK');
+like($_, qr{^<(\w+)\s*>ELEMELEMELEM</\1>$}, 'document OK');
+
+
+# Try again with multiple groupings
+
+$ref = {
+ dirs => [ '/usr/bin', '/usr/local/bin' ],
+ terms => [ 'vt100', 'xterm' ],
+};
+
+# Expect:
+#
+# <opt>
+# <dirs>
+# <dir>/usr/bin</dir>
+# <dir>/usr/local/bin</dir>
+# </dirs>
+# <terms>
+# <term>vt100</term>
+# <term>xterm</term>
+# </terms>
+# </opt>
+#
+
+$_ = XMLout($ref, grouptags => {dirs => 'dir', terms => 'term'}, noattr => 1);
+
+ok(s{\s*<dir>/usr/bin</dir>\s*<dir>/usr/local/bin</dir>\s*}{LIST}s, 'list 1 OK');
+ok(s{\s*<dirs>LIST</dirs>\s*}{ELEM}s, 'group 1 OK');
+ok(s{\s*<term>vt100</term>\s*<term>xterm</term>\s*}{LIST}s, 'list 2 OK');
+ok(s{\s*<terms>LIST</terms>\s*}{ELEM}s, 'group 2 OK');
+like($_, qr{^<(\w+)\s*>ELEMELEM</\1>$}, 'document OK');
+
+
+# Confirm unfolding and grouping work together
+
+$ref = {
+ dirs => {
+ first => { content => '/usr/bin' },
+ second => { content => '/usr/local/bin' },
+ },
+};
+
+# Expect:
+#
+# <opt>
+# <dirs>
+# <dir name="first">/usr/bin</dir>
+# <dir name="second">/usr/local/bin</dir>
+# </dirs>
+# </opt>
+#
+
+$_ = XMLout($ref,
+ grouptags => {dirs => 'dir'}, keyattr => {dir => 'name'},
+);
+
+ok(s{\s*<dir\s+name="first">/usr/bin</dir>\s*}{ITEM}s, 'item 1 OK');
+ok(s{\s*<dir\s+name="second">/usr/local/bin</dir>\s*}{ITEM}s, 'item 2 OK');
+ok(s{\s*<dirs>ITEMITEM</dirs>\s*}{GROUP}s, 'group OK');
+like($_, qr{^<(\w+)\s*>GROUP</\1>$}, 'document OK');
+
+
+# Combine unfolding, grouping and stripped content - watch it fail :-(
+
+$ref = {
+ dirs => {
+ first => '/usr/bin',
+ second => '/usr/local/bin'
+ },
+};
+
+# Expect:
+#
+# <opt>
+# <dirs first="/usr/bin" second="/usr/local/bin" />
+# </opt>
+#
+
+$_ = XMLout($ref,
+ grouptags => {dirs => 'dir'}, keyattr => {dir => 'name'},
+ contentkey => '-content'
+);
+
+like($_, qr{
+ ^<(\w+)>\s*
+ <dirs>\s*
+ <dir
+ (?:
+ \s+first="/usr/bin"
+ |\s+second="/usr/local/bin"
+ ){2}\s*
+ />\s*
+ </dirs>\s*
+ </\1>$
+}x, 'Failed to unwrap/group stripped content - as expected');
# 'Stress test' with a data structure that maps to several thousand elements.
Index: 3_Storable.t
===================================================================
RCS file: /cvsroot/perl-xml/xml-simple/t/3_Storable.t,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- 3_Storable.t 16 Oct 2002 09:43:35 -0000 1.5
+++ 3_Storable.t 10 Apr 2003 10:20:08 -0000 1.6
@@ -36,7 +36,7 @@
}
-plan tests => 20;
+plan tests => 21;
##############################################################################
# S U P P O R T R O U T I N E S
@@ -175,6 +175,11 @@
PassTime($t1);
$opt = XMLin($XMLFile, cache => 'storable');
is_deeply($opt, $Expected, 'parsed expected data in through cache');
+
+# Make sure scheme name is case-insensitive
+
+$opt = XMLin($XMLFile, cache => 'Storable');
+is_deeply($opt, $Expected, 'scheme name is case-insensitive');
# Clean up and go
Index: 6_ObjIntf.t
===================================================================
RCS file: /cvsroot/perl-xml/xml-simple/t/6_ObjIntf.t,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- 6_ObjIntf.t 16 Oct 2002 09:43:35 -0000 1.4
+++ 6_ObjIntf.t 10 Apr 2003 10:20:08 -0000 1.5
@@ -2,7 +2,7 @@
# vim: syntax=perl
use strict;
-use Test::More tests => 27;
+use Test::More tests => 33;
##############################################################################
# Derived version of XML::Simple that returns everything in upper case
@@ -101,10 +101,19 @@
keyattr => { }
);
+my %opts3 = (
+ keyattr => { disc => 'cddbid', track => 'number' },
+ keeproot => 1,
+ contentkey => '-title',
+ forcearray => [ qw(disc album) ]
+);
+
my $xs1 = new XML::Simple( %opts1 );
my $xs2 = new XML::Simple( %opts2 );
+my $xs3 = new XML::Simple( %opts3 );
isa_ok($xs1, 'XML::Simple', 'object one');
isa_ok($xs2, 'XML::Simple', 'object two');
+isa_ok($xs3, 'XML::Simple', 'object three');
is_deeply(\%opts1, {
keyattr => { disc => 'cddbid', track => 'number' },
keeproot => 1,
@@ -171,6 +180,38 @@
is_deeply($ref2, $exp2, 'parsed expected data via object 2');
+# Try using the third object
+
+my $exp3 = {
+ 'cddatabase' => {
+ 'disc' => {
+ '960b750c' => {
+ 'id' => '9362-45055-2',
+ 'album' => [ 'Automatic For The People' ],
+ 'artist' => 'R.E.M.',
+ 'track' => {
+ 1 => 'Drive',
+ 2 => 'Try Not To Breathe',
+ 3 => 'The Sidewinder Sleeps Tonite',
+ 4 => 'Everybody Hurts',
+ 5 => 'New Orleans Instrumental No. 1',
+ 6 => 'Sweetness Follows',
+ 7 => 'Monty Got A Raw Deal',
+ 8 => 'Ignoreland',
+ 9 => 'Star Me Kitten',
+ 10 => 'Man On The Moon',
+ 11 => 'Nightswimming',
+ 12 => 'Find The River'
+ }
+ }
+ }
+ }
+};
+
+my $ref3 = $xs3->XMLin($xml);
+is_deeply($ref3, $exp3, 'parsed expected data via object 3');
+
+
# Confirm default options in object merge correctly with options as args
$ref1 = $xs1->XMLin($xml, keyattr => [], forcearray => 0);
@@ -266,3 +307,53 @@
like($_, qr{<opt>\s*
<server\s+address="<!\[CDATA\[12->14\s+"Puf&Stuf"\s+Drive\]\]>"\s*/>\s*
</opt>}xs, 'inheritance works with escape_value() overridden');
+
+
+# Check variables defined in the constructor don't get trounced for
+# subsequent parses
+
+$xs1 = XML::Simple->new(
+ contentkey => '-content',
+ varattr => 'xsvar',
+ variables => { conf_dir => '/etc', log_dir => '/tmp' }
+);
+
+$xml = q(<opt>
+ <dir xsvar="log_dir">/var/log</dir>
+ <file name="config_file">${conf_dir}/appname.conf</file>
+ <file name="log_file">${log_dir}/appname.log</file>
+ <file name="debug_file">${log_dir}/appname.dbg</file>
+</opt>);
+
+my $opt = $xs1->XMLin($xml);
+is_deeply($opt, {
+ file => {
+ config_file => '/etc/appname.conf',
+ log_file => '/var/log/appname.log',
+ debug_file => '/var/log/appname.dbg',
+ },
+ dir => { xsvar => 'log_dir', content => '/var/log' },
+}, 'variables from XML merged with predefined variables');
+
+$xml = q(<opt>
+ <file name="config_file">${conf_dir}/appname.conf</file>
+ <file name="log_file">${log_dir}/appname.log</file>
+ <file name="debug_file">${log_dir}/appname.dbg</file>
+</opt>);
+
+my $opt = $xs1->XMLin($xml);
+is_deeply($opt, {
+ file => {
+ config_file => '/etc/appname.conf',
+ log_file => '/tmp/appname.log',
+ debug_file => '/tmp/appname.dbg',
+ },
+}, 'variables from XML merged with predefined variables');
+
+# check that unknown options passed to the constructor are rejected
+
+$@ = undef;
+eval { $xs1 = XML::Simple->new(KeyAttr => {}, WibbleFlibble => 1) };
+ok(defined($@), "unrecognised option caught by constructor");
+like($@, qr/^Unrecognised option: WibbleFlibble at/,
+ "correct message in exception");
Index: 9_Strict.t
===================================================================
RCS file: /cvsroot/perl-xml/xml-simple/t/9_Strict.t,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- 9_Strict.t 11 Dec 2002 01:48:28 -0000 1.3
+++ 9_Strict.t 10 Apr 2003 10:20:10 -0000 1.4
@@ -36,7 +36,7 @@
};
isnt($@, '', 'omitting forcearray was a fatal error');
-like($@, qr/No value specified for 'forcearray'/,
+like($@, qr/(?i)No value specified for 'forcearray'/,
'with the correct error message');
@@ -47,7 +47,7 @@
};
isnt($@, '', 'omitting keyattr was a fatal error');
-like($@, qr/No value specified for 'keyattr'/,
+like($@, qr/(?i)No value specified for 'keyattr'/,
'with the correct error message');
@@ -58,7 +58,7 @@
};
isnt($@, '', 'omitting forcearray for elements in keyattr was a fatal error');
-like($@, qr/<part> set in keyattr but not in forcearray/,
+like($@, qr/(?i)<part> set in keyattr but not in forcearray/,
'with the correct error message');
@@ -67,7 +67,7 @@
};
isnt($@, '', 'omitting keyattr elements from forcearray was a fatal error');
-like($@, qr/<part> set in keyattr but not in forcearray/,
+like($@, qr/(?i)<part> set in keyattr but not in forcearray/,
'with the correct error message');
@@ -86,7 +86,7 @@
};
isnt($@, '', 'key attribute missing from names element was a fatal error');
-like($@, qr/<part> element has no 'partnum' key attribute/,
+like($@, qr/(?i)<part> element has no 'partnum' key attribute/,
'with the correct error message');
@@ -106,7 +106,7 @@
};
isnt($@, '', 'key attribute not a scalar was a fatal error');
-like($@, qr/<item> element has non-scalar 'name' key attribute/,
+like($@, qr/(?i)<item> element has non-scalar 'name' key attribute/,
'with the correct error message');
@@ -145,7 +145,7 @@
};
isnt($@, '', 'omitting keyattr was a fatal error');
-like($@, qr/No value specified for 'keyattr'/,
+like($@, qr/(?i)No value specified for 'keyattr'/,
'with the correct error message');
@@ -179,7 +179,7 @@
};
isnt($@, '', 'omitting forcearray was a fatal error');
-like($@, qr/No value specified for 'forcearray'/,
+like($@, qr/(?i)No value specified for 'forcearray'/,
'with the correct error message');
@@ -192,7 +192,7 @@
};
isnt($@, '', 'omitting keyattr was a fatal error');
-like($@, qr/No value specified for 'keyattr'/,
+like($@, qr/(?i)No value specified for 'keyattr'/,
'with the correct error message');
@@ -205,7 +205,7 @@
};
isnt($@, '', 'omitting forcearray for elements in keyattr was a fatal error');
-like($@, qr/<part> set in keyattr but not in forcearray/,
+like($@, qr/(?i)<part> set in keyattr but not in forcearray/,
'with the correct error message');
@@ -216,7 +216,7 @@
};
isnt($@, '', 'omitting keyattr elements from forcearray was a fatal error');
-like($@, qr/<part> set in keyattr but not in forcearray/,
+like($@, qr/(?i)<part> set in keyattr but not in forcearray/,
'with the correct error message');
@@ -236,7 +236,7 @@
};
isnt($@, '', 'key attribute missing from names element was a fatal error');
-like($@, qr/<part> element has no 'partnum' key attribute/,
+like($@, qr/(?i)<part> element has no 'partnum' key attribute/,
'with the correct error message');
@@ -258,7 +258,7 @@
};
isnt($@, '', 'key attribute not a scalar was a fatal error');
-like($@, qr/<item> element has non-scalar 'name' key attribute/,
+like($@, qr/(?i)<item> element has non-scalar 'name' key attribute/,
'with the correct error message');
@@ -301,7 +301,7 @@
};
isnt($@, '', 'omitting keyattr was a fatal error');
-like($@, qr/No value specified for 'keyattr'/,
+like($@, qr/(?i)No value specified for 'keyattr'/,
'with the correct error message');
|