The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/env perl
# test facets

use warnings;
use strict;

use lib 'lib','t';
use TestTools;

use XML::Compile::Schema;
use XML::Compile::Tester;
use XML::Compile::Util qw/pack_type/;

use Test::More tests => 374;

set_compile_defaults
    elements_qualified => 'NONE';

my $schema   = XML::Compile::Schema->new( <<__SCHEMA__ );
<schema targetNamespace="$TestNS"
        xmlns="$SchemaNS"
        xmlns:me="$TestNS"
        elementFormDefault="qualified">

<simpleType name="t1">
  <restriction base="int" />
</simpleType>

<simpleType name="t2">
  <restriction base="int">
    <maxInclusive value="42" />
    <minInclusive value="12" />
  </restriction>
</simpleType>

<element name="test1" type="me:t1" />

<element name="test2" type="me:t2" />

<element name="test3">
  <simpleType>
    <restriction base="int">
      <maxExclusive value="45" />
      <minExclusive value="13" />
    </restriction>
  </simpleType>
</element>

<element name="test4">
  <simpleType>
    <restriction base="string">
      <length value="3" />
    </restriction>
  </simpleType>
</element>

<element name="test5">
  <simpleType>
    <restriction base="string">
      <whiteSpace value="preserve" />
    </restriction>
  </simpleType>
</element>

<element name="test6">
  <simpleType>
    <restriction base="string">
      <whiteSpace value="replace" />
    </restriction>
  </simpleType>
</element>

<element name="test7">
  <simpleType>
    <restriction base="string">
      <whiteSpace value="collapse" />
    </restriction>
  </simpleType>
</element>

<element name="test8">
  <simpleType>
    <restriction base="string">
      <enumeration value="one" />
      <enumeration value="two" />
    </restriction>
  </simpleType>
</element>

<element name="test9">
  <simpleType>
    <restriction base="long">
      <totalDigits value="4" />
    </restriction>
  </simpleType>
</element>

<element name="test10">
  <simpleType>
    <restriction base="float">
      <totalDigits value="4" />
    </restriction>
  </simpleType>
</element>

<element name="test11">
  <complexType>
    <sequence>
      <element name="t11" type="me:t2" />
    </sequence>
  </complexType>
</element>

<!-- rt.cpan.org#39224, order of pattern match and value decoding -->
<simpleType name="DecimalType">
  <restriction base="decimal">
    <pattern value="[0-9]{1,13}\\.[0-9]{0,2}"/>
  </restriction>
</simpleType>
<element name="test12" type="me:DecimalType" />

<element name="test13">
  <simpleType>
    <restriction base="base64Binary">
      <length value="5"/>
    </restriction>
  </simpleType>
</element>

<!-- rt.cpan.org#62237, enumeration of qname -->
<element name="test14">
  <simpleType>
    <restriction base="QName">
      <enumeration value="me:DataEncodingUnknown"/>
      <enumeration value="me:MustUnderstand"/>
      <enumeration value="me:Receiver"/>
      <enumeration value="me:Sender"/>
      <enumeration value="me:VersionMismatch"/>
    </restriction>
  </simpleType>
</element>

<!-- from KML 2.2 -->
<element name="test15" type="me:colorType" />
<simpleType name="colorType">
  <annotation>
    <documentation><![CDATA[
        
        aabbggrr
        
        ffffffff: opaque white
        ff000000: opaque black
        
        ]]></documentation>
  </annotation>
  <restriction base="hexBinary">
    <length value="4"/>
  </restriction>
</simpleType>

<!-- rt.cpan.org#63464, combined totalDigits and fracDigits -->
<element name="test16">
  <simpleType>
    <restriction base="decimal">
      <fractionDigits value="2" />
    </restriction>
  </simpleType>
</element>

<element name="test17">
  <simpleType>
    <restriction base="decimal">
      <totalDigits value="5" />
      <fractionDigits value="2" />
    </restriction>
  </simpleType>
</element>

<!-- Question by andrew campbell, 2013-02-08 -->
<element name="test18">
  <simpleType>
    <restriction base="dateTime">
      <minInclusive value="1995-01-01T00:00:00Z"/>
      <maxInclusive value="2120-12-31T00:00:00Z"/>
    </restriction>
  </simpleType>
</element>

</schema>
__SCHEMA__

ok(defined $schema);

##
### Integers
##

test_rw($schema, test1 => <<__XML, 12);
<test1>12</test1>
__XML

test_rw($schema, test2 => <<__XML, 13);
<test2>13</test2>
__XML

test_rw($schema, test2 => <<__XML, 42);
<test2>42</test2>
__XML

my $error = error_r($schema, test2 => <<__XML);
<test2>43</test2>
__XML
is($error, "too large inclusive 43, max 42 at {http://test-types}test2#facet");

$error = error_w($schema, test2 => 43);
is($error, "too large inclusive 43, max 42 at {http://test-types}test2#facet");

$error = error_r($schema, test2 => <<__XML);
<test2>11</test2>
__XML
is($error, "too small inclusive 11, min 12 at {http://test-types}test2#facet");

$error = error_w($schema, test2 => 11);
is($error, "too small inclusive 11, min 12 at {http://test-types}test2#facet");

test_rw($schema, "test3" => <<__XML, 44);
<test3>44</test3>
__XML

$error = error_r($schema, test3 => <<__XML);
<test3>45</test3>
__XML
is($error, "too large exclusive 45, smaller 45 at {http://test-types}test3#facet");

$error = error_w($schema, test3 => 45);
is($error, "too large exclusive 45, smaller 45 at {http://test-types}test3#facet");

$error = error_r($schema, test3 => <<__XML);
<test3>13</test3>
__XML
is($error, "too small exclusive 13, larger 13 at {http://test-types}test3#facet");

$error = error_w($schema, test3 => 13);
is($error, "too small exclusive 13, larger 13 at {http://test-types}test3#facet");

##
### strings
##

test_rw($schema, "test4" => <<__XML, "aap");
<test4>aap</test4>
__XML

$error = error_r($schema, test4 => <<__XML);
<test4>noot</test4>
__XML

is($error, "string `noot' does not have required length 3 but 4 at {http://test-types}test4\#facet");

$error = error_w($schema, test4 => 'noot');
is($error, "string `noot' does not have required length 3 but 4 at {http://test-types}test4\#facet");

$error = error_r($schema, test4 => <<__XML);
<test4>ik</test4>
__XML
is($error, "string `ik' does not have required length 3 but 2 at {http://test-types}test4#facet");

$error = error_w($schema, test4 => "ik");
is($error,  "string `ik' does not have required length 3 but 2 at {http://test-types}test4#facet");

test_rw($schema, "test5" => <<__XML, "\ \ \t\n\tmies \t");
<test5>\ \ \t
\tmies \t</test5>
__XML

test_rw($schema, "test6" => <<__XML, "     mies  ", <<__XML, "\ \ \t \tmies \t");
<test6>\ \ \t
\tmies \t</test6>
__XML
<test6>     mies  </test6>
__XML

test_rw($schema, "test7" => <<__XML, 'mies', <<__XML, "\ \ \t \tmies \t");
<test7>\ \ \t
\tmies \t</test7>
__XML
<test7>mies</test7>
__XML

test_rw($schema, "test8" => <<__XML, 'one');
<test8>one</test8>
__XML

test_rw($schema, "test8" => <<__XML, 'two');
<test8>two</test8>
__XML

$error = error_r($schema, test8 => <<__XML);
<test8>three</test8>
__XML
is($error, "invalid enumerate `three' at {http://test-types}test8#facet");

$error = error_r($schema, test8 => <<__XML);
<test8/>
__XML
is($error, "invalid enumerate `' at {http://test-types}test8#facet");

### test9 (bug reported by Gert Doering)

set_compile_defaults
   sloppy_integers    => 1
 , sloppy_floats      => 1
 , elements_qualified => 'NONE';

test_rw($schema, test9 => '<test9>0</test9>', 0);

test_rw($schema, test9 => '<test9>12</test9>', 12);

test_rw($schema, test9 => '<test9>123</test9>', 123);

test_rw($schema, test9 => '<test9>1234</test9>', 1234);

$error = error_w($schema, test9 => 12345);
is($error, 'decimal too long, got 5 digits max 4 at {http://test-types}test9#facet');

$error = error_r($schema, test9 => '<test9>12345</test9>');
is($error, 'decimal too long, got 5 digits max 4 at {http://test-types}test9#facet');

### test10 (same bug reported by Gert Doering)

test_rw($schema, test10 => '<test10>0</test10>', 0);
test_rw($schema, test10 => '<test10>1.2</test10>', 1.2);
test_rw($schema, test10 => '<test10>1.23</test10>', 1.23);
test_rw($schema, test10 => '<test10>12.3</test10>', 12.3);
test_rw($schema, test10 => '<test10>1.234</test10>', 1.234);
test_rw($schema, test10 => '<test10>12.34</test10>', 12.34);
test_rw($schema, test10 => '<test10>123.4</test10>', 123.4);
test_rw($schema, test10 => '<test10>1234</test10>', 1234);

### test11 (from bug reported by Allan Wind)

$error = error_w($schema, test11 => {t11 => 3});
is($error, 'too small inclusive 3, min 12 at {http://test-types}test11/t11#facet');

### test12 rt.cpan.org#39224

test_rw($schema, test12 => '<test12>1.12</test12>', '1.12');
test_rw($schema, test12 => '<test12>1.10</test12>', '1.10');
test_rw($schema, test12 => '<test12>1.00</test12>', '1.00');
test_rw($schema, test12 => '<test12>1.2</test12>',  '1.2');
test_rw($schema, test12 => '<test12>1.</test12>',   '1.');

$error = error_r($schema, test12 => '<test12>1</test12>');
like($error, qr/^string \`1' does not match pattern /);

# dot problem with regex '.'
$error = error_r($schema, test12 => '<test12>42</test12>');
like($error, qr/^string \`42' does not match pattern /);

### test13 length on base64

test_rw($schema, test13 => '<test13>YWJjZGU=</test13>', 'abcde');

$error = error_r($schema, test13 => '<test13>YWJjYWJjZGU=</test13>');
is($error, "string `abcabcde' does not have required length 5 but 8 at {http://test-types}test13#facet");

$error = error_w($schema, test13 => 'abcdef');
is($error, "base64 data does not have required length 5, but 6 at {http://test-types}test13#facet");

### test15 length of hexBinary

test_rw($schema, test15 => '<test15>DEADBEEF</test15>', pack('N', 0xdeadbeef));

$error = error_r($schema, test15 => '<test15>345678</test15>');
is($error, "string `4Vx' does not have required length 4 but 3 at {http://test-types}test15#facet");

$error = error_w($schema, test15 => 'abc');
is($error, "hex data does not have required length 4, but 3 at {http://test-types}test15#facet");

$error = error_w($schema, test15 => 'anything');
is($error, "hex data does not have required length 4, but 8 at {http://test-types}test15#facet");

### test14 enumeration of qnames [Aleksey Mashanov]

set_compile_defaults
    include_namespaces    => 1
  , use_default_namespace => 0
  , prefixes => [ a => $TestNS ];

test_rw($schema, test14 => qq{<a:test14 xmlns:a="$TestNS">a:Sender</a:test14>}
  , "{$TestNS}Sender");

### test16 fracDigits

# max 2 digits
my $t16 = pack_type $TestNS, 'test16';
my $r16 = reader_create $schema, "frac 2r", $t16;
is($r16->(qq{<test16 xmlns="$TestNS">2.14</test16>}), "2.14");
is($r16->(qq{<test16 xmlns="$TestNS">3.1</test16>}), "3.1");

# this actually should cause an error!
is($r16->(qq{<test16 xmlns="$TestNS">3.14152</test16>}), "3.14");

my $w16 = writer_create $schema, 'frac 2w', $t16;
my $x16 = writer_test $w16, '3.141526';
compare_xml($x16, qq{<a:test16 xmlns:a="$TestNS">3.14</a:test16>});

### test17, totalFracDigits [mimon-cz]

my $t17 = pack_type $TestNS, 'test17';
my $r17 = reader_create $schema, "total 5, frac 2r", $t17;
is($r17->(qq{<test17 xmlns="$TestNS">2.14</test17>}), "2.14");
is($r17->(qq{<test17 xmlns="$TestNS">3.1</test17>}), "3.1");
is($r17->(qq{<test17 xmlns="$TestNS">3.14152</test17>}), "3.14");

my $w17 = writer_create $schema, 'total 5, frac 2w', $t17;
my $x17 = writer_test $w17, '3.141526';
compare_xml($x17, qq{<a:test17 xmlns:a="$TestNS">3.14</a:test17>});

### test18
set_compile_defaults
    include_namespaces    => 0
  , elements_qualified    => 'NONE'
  , use_default_namespace => 0;

test_rw($schema, test18 => '<test18>2012-01-01T00:00:00Z</test18>'
  , '2012-01-01T00:00:00Z');