# frozen_string_literal: false
require "test/unit/testcase"

require "rexml/document"
require "rexml/validation/relaxng"

module REXMLTests
  class RNGValidation < Test::Unit::TestCase
    include REXML

    def test_validate
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <element name="B">
    <element name="C">
      <attribute name="X"/>
      <zeroOrMore>
        <element name="E">
          <empty/>
        </element>
      </zeroOrMore>
    </element>
    <element name="D">
      <empty/>
    </element>
  </element>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      no_error( validator, %q{<A><B><C X="x"><E/><E/></C><D/></B></A>} )
      error( validator, %q{<A><B><D/><C X="x"/></B></A>} )
    end


    def test_sequence
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <element name="B">
    <element name="C">
      <empty/>
    </element>
    <element name="D">
      <empty/>
    </element>
  </element>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B><C/><C/><D/></B></A>} )
      error( validator, %q{<A><B><D/><C/></B></A>} )
      error( validator, %q{<A><C/><D/></A>} )
      no_error( validator, %q{<A><B><C/><D/></B></A>} )
    end


    def test_choice
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <element name="B">
    <choice>
      <element name="C">
        <empty/>
      </element>
      <element name="D">
        <empty/>
      </element>
    </choice>
  </element>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B><C/><D/></B></A>} )
      no_error( validator, %q{<A><B><D/></B></A>} )
      no_error( validator, %q{<A><B><C/></B></A>} )
    end

    def test_optional
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <element name="B">
    <optional>
      <element name="C">
        <empty/>
      </element>
    </optional>
  </element>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      no_error( validator, %q{<A><B/></A>} )
      no_error( validator, %q{<A><B><C/></B></A>} )
      error( validator, %q{<A><B><D/></B></A>} )
      error( validator, %q{<A><B><C/><C/></B></A>} )
    end

    def test_zero_or_more
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <element name="B">
    <zeroOrMore>
      <element name="C">
        <empty/>
      </element>
    </zeroOrMore>
  </element>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )
      no_error( validator, %q{<A><B/></A>} )
      no_error( validator, %q{<A><B><C/></B></A>} )
      no_error( validator, %q{<A><B><C/><C/><C/></B></A>} )
      error( validator, %q{<A><B><D/></B></A>} )
      error( validator, %q{<A></A>} )

      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <element name="B">
    <zeroOrMore>
      <element name="C">
        <empty/>
      </element>
      <element name="D">
        <empty/>
      </element>
    </zeroOrMore>
  </element>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      no_error( validator, %q{<A><B/></A>} )
      no_error( validator, %q{<A><B><C/><D/></B></A>} )
      no_error( validator, %q{<A><B><C/><D/><C/><D/></B></A>} )
      error( validator, %q{<A><B><D/></B></A>} )
    end

    def test_one_or_more
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <element name="B">
    <oneOrMore>
      <element name="C">
        <empty/>
      </element>
    </oneOrMore>
  </element>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B/></A>} )
      no_error( validator, %q{<A><B><C/></B></A>} )
      no_error( validator, %q{<A><B><C/><C/><C/></B></A>} )
      error( validator, %q{<A><B><D/></B></A>} )
      error( validator, %q{<A></A>} )
    end

    def test_attribute
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <attribute name="X"/>
  <attribute name="Y"/>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B/></A>} )
      error( validator, %q{<A/>} )
      error( validator, %q{<A X=""/>} )
      no_error( validator, %q{<A X="1" Y="1"/>} )
    end

    def test_choice_attributes
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <choice>
    <attribute name="X"/>
    <attribute name="Y"/>
  </choice>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A X="1" Y="1"/>} )
      error( validator, %q{<A/>} )
      no_error( validator, %q{<A X="1"/>})
      no_error( validator, %q{<A Y="1"/>} )
    end

    def test_choice_attribute_element
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <choice>
    <attribute name="X"/>
    <element name="B"/>
  </choice>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A X="1"><B/></A>} )
      error( validator, %q{<A/>} )
      no_error( validator, %q{<A X="1"/>})
      no_error( validator, %q{<A><B/></A>} )
    end

    def test_empty
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <empty/>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B/></A>} )
      error( validator, %q{<A>Text</A>} )
      no_error( validator, %q{<A/>})
    end

    def test_text_val
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <text/>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B/></A>} )
      no_error( validator, %q{<A>Text</A>} )
      error( validator, %q{<A/>})
    end

    def test_choice_text
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <choice>
    <element name="B"/>
    <text/>
  </choice>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B/>Text</A>} )
      error( validator, %q{<A>Text<B/></A>} )
      no_error( validator, %q{<A>Text</A>} )
      no_error( validator, %q{<A><B/></A>} )
    end

    def test_group
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <choice>
    <element name="B"/>
    <group>
      <element name="C"/>
      <element name="D"/>
    </group>
  </choice>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B/><C/></A>} )
      error( validator, %q{<A><C/></A>} )
      no_error( validator, %q{<A><B/></A>} )
      no_error( validator, %q{<A><C/><D/></A>} )

      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <element name="B"/>
  <group>
    <element name="C"/>
    <element name="D"/>
  </group>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B/><C/></A>} )
      error( validator, %q{<A><B/><D/></A>} )
      error( validator, %q{<A><B/></A>} )
      no_error( validator, %q{<A><B/><C/><D/></A>} )
    end

    def test_value
      # Values as text nodes
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <element name="B">
    <value>VaLuE</value>
  </element>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B>X</B></A>} )
      error( validator, %q{<A><B/></A>} )
      no_error( validator, %q{<A><B>VaLuE</B></A>} )

      # Values as text nodes, via choice
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <element name="B">
    <choice>
      <value>Option 1</value>
      <value>Option 2</value>
    </choice>
  </element>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B/></A>} )
      error( validator, %q{<A><B>XYZ</B></A>} )
      no_error( validator, %q{<A><B>Option 1</B></A>} )
      no_error( validator, %q{<A><B>Option 2</B></A>} )

      # Attribute values
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <attribute name="B">
    <value>VaLuE</value>
  </attribute>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A/>} )
      error( validator, %q{<A B=""/>} )
      error( validator, %q{<A B="Lala"/>} )
      no_error( validator, %q{<A B="VaLuE"/>} )

      # Attribute values via choice
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <attribute name="B">
    <choice>
      <value>Option 1</value>
      <value>Option 2</value>
    </choice>
  </attribute>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A B=""/>} )
      error( validator, %q{<A B="Value"/>} )
      no_error( validator, %q{<A B="Option 1"></A>} )
      no_error( validator, %q{<A B="Option 2"/>} )
    end

    def test_interleave
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <element name="B">
    <interleave>
      <element name="C"/>
      <element name="D"/>
      <element name="E"/>
    </interleave>
  </element>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B><C/></B></A>} )
      error( validator, %q{<A><B><C/><D/><C/></B></A>} )
      no_error( validator, %q{<A><B><C/><D/><E/></B></A>} )
      no_error( validator, %q{<A><B><E/><D/><C/></B></A>} )
      no_error( validator, %q{<A><B><D/><C/><E/></B></A>} )
      no_error( validator, %q{<A><B><E/><C/><D/></B></A>} )
      error( validator, %q{<A><B><E/><C/><D/><C/></B></A>} )
    end

    def test_mixed
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<element name="A" xmlns="http://relaxng.org/ns/structure/1.0">
  <element name="B">
    <mixed>
      <element name="D"/>
    </mixed>
  </element>
</element>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      no_error( validator, %q{<A><B>Text<D/></B></A>} )
      no_error( validator, %q{<A><B><D/>Text</B></A>} )
    end

    def test_ref_sequence
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
  <start>
    <element name="A">
      <ref name="B"/>
      <ref name="B"/>
    </element>
  </start>

  <define name="B">
    <element name="B">
      <attribute name="X"/>
    </element>
  </define>
</grammar>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      no_error( validator, %q{<A><B X=''/><B X=''/></A>} )
      error( validator, %q{<A><B X=''/></A>} )
    end

    def test_ref_choice
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
  <start>
    <element name="A">
      <choice>
        <ref name="B"/>
      </choice>
    </element>
  </start>

  <define name="B">
    <element name="B"/>
    <element name="C"/>
  </define>
</grammar>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><D/></A>} )
      error( validator, %q{<A><B/><C/></A>} )
      no_error( validator, %q{<A><B/></A>} )
      no_error( validator, %q{<A><C/></A>} )

      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
  <start>
    <element name="A">
      <ref name="B"/>
    </element>
  </start>

  <define name="B">
    <choice>
      <element name="B"/>
      <element name="C"/>
    </choice>
  </define>
</grammar>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><D/></A>} )
      error( validator, %q{<A><B/><C/></A>} )
      no_error( validator, %q{<A><B/></A>} )
      no_error( validator, %q{<A><C/></A>} )

      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
  <start>
    <element name="A">
      <choice>
        <ref name="B"/>
        <element name="D"/>
      </choice>
    </element>
  </start>

  <define name="B">
    <element name="B"/>
    <element name="C"/>
  </define>
</grammar>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B/><C/></A>} )
      no_error( validator, %q{<A><B/></A>} )
      no_error( validator, %q{<A><C/></A>} )
      no_error( validator, %q{<A><D/></A>} )
    end


    def test_ref_zero_plus
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
  <start>
    <element name="A">
      <zeroOrMore>
        <ref name="B"/>
      </zeroOrMore>
    </element>
  </start>

  <define name="B">
    <element name="B">
      <attribute name="X"/>
    </element>
  </define>
</grammar>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B/></A>} )
      no_error( validator, %q{<A/>} )
      no_error( validator, %q{<A><B X=''/></A>} )
      no_error( validator, %q{<A><B X=''/><B X=''/><B X=''/></A>} )

      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
  <start>
    <element name="A">
      <ref name="B"/>
    </element>
  </start>

  <define name="B">
    <zeroOrMore>
      <element name="B">
        <attribute name="X"/>
      </element>
    </zeroOrMore>
  </define>
</grammar>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B/></A>} )
      no_error( validator, %q{<A/>} )
      no_error( validator, %q{<A><B X=''/></A>} )
      no_error( validator, %q{<A><B X=''/><B X=''/><B X=''/></A>} )
    end


    def test_ref_one_plus
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
  <start>
    <element name="A">
      <oneOrMore>
        <ref name="B"/>
      </oneOrMore>
    </element>
  </start>

  <define name="B">
    <element name="B">
      <attribute name="X"/>
    </element>
  </define>
</grammar>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B/></A>} )
      error( validator, %q{<A/>} )
      no_error( validator, %q{<A><B X=''/></A>} )
      no_error( validator, %q{<A><B X=''/><B X=''/><B X=''/></A>} )

      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
  <start>
    <element name="A">
      <ref name="B"/>
    </element>
  </start>

  <define name="B">
    <oneOrMore>
      <element name="B">
        <attribute name="X"/>
      </element>
    </oneOrMore>
  </define>
</grammar>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B/></A>} )
      error( validator, %q{<A/>} )
      no_error( validator, %q{<A><B X=''/></A>} )
      no_error( validator, %q{<A><B X=''/><B X=''/><B X=''/></A>} )
    end

    def test_ref_interleave
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
  <start>
    <element name="A">
      <interleave>
        <ref name="B"/>
      </interleave>
    </element>
  </start>

  <define name="B">
    <element name="B"/>
    <element name="C"/>
  </define>
</grammar>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B/></A>} )
      error( validator, %q{<A><C/></A>} )
      error( validator, %q{<A><C/><C/></A>} )
      no_error( validator, %q{<A><B/><C/></A>} )
      no_error( validator, %q{<A><C/><B/></A>} )

      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
  <start>
    <element name="A">
      <ref name="B"/>
    </element>
  </start>

  <define name="B">
    <interleave>
      <element name="B"/>
      <element name="C"/>
    </interleave>
  </define>
</grammar>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B/></A>} )
      error( validator, %q{<A><C/></A>} )
      error( validator, %q{<A><C/><C/></A>} )
      no_error( validator, %q{<A><B/><C/></A>} )
      no_error( validator, %q{<A><C/><B/></A>} )

      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
  <start>
    <element name="A">
      <interleave>
        <ref name="B"/>
        <ref name="C"/>
      </interleave>
    </element>
  </start>

  <define name="B">
    <element name="B"/>
  </define>
  <define name="C">
    <element name="C"/>
  </define>
</grammar>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A><B/></A>} )
      error( validator, %q{<A><C/></A>} )
      error( validator, %q{<A><C/><C/></A>} )
      no_error( validator, %q{<A><B/><C/></A>} )
      no_error( validator, %q{<A><C/><B/></A>} )
    end

    def test_ref_recurse
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
  <start>
    <element name="A">
      <ref name="B"/>
    </element>
  </start>

  <define name="B">
    <element name="B">
      <optional>
        <ref name="B"/>
      </optional>
    </element>
  </define>
</grammar>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      error( validator, %q{<A></A>} )
      no_error( validator, %q{<A><B/></A>} )
      no_error( validator, %q{<A><B><B/></B></A>} )
    end

    def test_ref_optional
      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
  <start>
    <element name="A">
      <optional>
        <ref name="B"/>
      </optional>
    </element>
  </start>

  <define name="B">
    <element name="B">
    </element>
  </define>
</grammar>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      no_error( validator, %q{<A></A>} )
      no_error( validator, %q{<A><B/></A>} )
      error( validator, %q{<A><B/><B/></A>} )
      error( validator, %q{<A><C/></A>} )

      rng = %q{
<?xml version="1.0" encoding="UTF-8"?>
<grammar xmlns="http://relaxng.org/ns/structure/1.0">
  <start>
    <element name="A">
      <ref name="B"/>
    </element>
  </start>

  <define name="B">
    <optional>
      <element name="B">
      </element>
    </optional>
  </define>
</grammar>
      }
      validator = REXML::Validation::RelaxNG.new( rng )

      no_error( validator, %q{<A></A>} )
      no_error( validator, %q{<A><B/></A>} )
      error( validator, %q{<A><B/><B/></A>} )
      error( validator, %q{<A><C/></A>} )
    end



    def error( validator, source )
      parser = REXML::Parsers::TreeParser.new( source )
      parser.add_listener( validator.reset )
      assert_raise( REXML::Validation::ValidationException,
                    "Expected a validation error" ) { parser.parse }
    end

    def no_error( validator, source )
      parser = REXML::Parsers::TreeParser.new( source )
      parser.add_listener( validator.reset )
      assert_nothing_raised { parser.parse }
    end
  end
end
