<commit_before>/**
 * Copyright (C) 2011 Orbeon, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation; either version
 * 2.1 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * The full text of the license is available at http://www.gnu.org/copyleft/lesser.html
 */
package org.orbeon.oxf.xforms.control.controls

import XXFormsDynamicControl._
import org.junit.Test
import org.orbeon.oxf.test.DocumentTestBase
import org.orbeon.oxf.xforms.control.controls.InstanceMirror._
import org.scalatest.junit.AssertionsForJUnit
import org.orbeon.oxf.xforms.XFormsConstants.COMPONENT_SEPARATOR
import org.orbeon.oxf.xml.Dom4j.elemToDocument

class InstanceMirrorTest extends DocumentTestBase with AssertionsForJUnit {

    @Test def mirrorInSamePart(): Unit = {
        this setupDocument
            <xh:html xmlns:xh="http://www.w3.org/1999/xhtml"
                     xmlns:xf="http://www.w3.org/2002/xforms"
                     xmlns:ev="http://www.w3.org/2001/xml-events"
                     xmlns:xxf="http://orbeon.org/oxf/xml/xforms">

                <xh:head>
                    <xf:model id="model">
                        <xf:instance id="form-instance" xxf:exclude-result-prefixes="#all">
                            <xh:html>
                                <xh:head>
                                    <xf:model id="my-model">
                                        <xf:instance id="my-instance">
                                            <instance/>
                                        </xf:instance>
                                    </xf:model>
                                </xh:head>
                                <xh:body/>
                            </xh:html>
                        </xf:instance>

                        <xf:instance id="my-instance" xxf:exclude-result-prefixes="#all">
                            <instance xmlns=""/>
                        </xf:instance>

                        <xf:insert   ev:event="update1"  context="//xf:instance/instance"   origin="xf:element('first', 'Arthur')"/>
                        <xf:insert   ev:event="update2"  ref="//xf:instance/instance/first" origin="xf:element('last', 'Clark')"    position="after"/>
                        <xf:insert   ev:event="update3"  ref="//xf:instance/instance/last"  origin="xf:element('middle', 'C.')"     position="before"/>
                        <xf:setvalue ev:event="update4"  ref="//xf:instance/instance/last">Clarke</xf:setvalue>
                        <xf:delete   ev:event="update5"  ref="//xf:instance/instance/*"/>
                        <xf:insert   ev:event="update6"  context="//xf:instance/instance"   origin="xf:attribute('first', 'Arthur')"/>
                        <xf:insert   ev:event="update7"  ref="//xf:instance/instance/@*"    origin="xf:attribute('last', 'Clarke')" position="after"/>
                        <xf:setvalue ev:event="update8"  ref="//xf:instance/instance/@last"><NAME></xf:setvalue>
                        <xf:delete   ev:event="update9"  ref="//xf:instance/instance/@*"/>
                        <xf:insert   ev:event="update10" context="/*/xh:body"               origin="xf:element('xh:div')"/>
                        <xf:setvalue ev:event="update11" ref="/*/xh:body/xh:div">Hello!</xf:setvalue>
                    </xf:model>
                </xh:head>
                <xh:body/>
            </xh:html>

        implicit val logger = document.indentedLogger

        val outerInstance = document.findInstance("form-instance").get
        val innerInstance = document.findInstance("my-instance").get

        var nonInstanceChanges = 0

        // Attach listeners
        val outerListener = {

            val unknownChange: MirrorEventListener = _ ⇒ {
                nonInstanceChanges += 1
                true
            }

            val outerMirrorListener =
                mirrorListener(
                    document,
                    toInnerInstanceNode(
                        outerInstance.documentInfo,
                        document.getStaticState.topLevelPart,
                        document,
                        findOuterInstanceDetailsDynamic
                    )
                )

            toEventListener(composeListeners(Seq(outerMirrorListener, unknownChange)))
        }

        addListener(outerInstance, outerListener)

        // Test insert, value change and delete
        val expected = Seq(
            ("""<instance><first>Arthur</first></instance>""", 0),
            ("""<instance><first>Arthur</first><last>Clark</last></instance>""" , 0),
            ("""<instance><first>Arthur</first><middle>C.</middle><last>Clark</last></instance>""" , 0),
            ("""<instance><first>Arthur</first><middle>C.</middle><last>Clarke</last></instance>""" , 0),
            ("""<instance/>""" , 0),
            ("""<instance first="Arthur"/>""" , 0),
            ("""<instance first="Arthur" last="Clarke"/>""" , 0),
            ("""<instance first="Arthur" last="<NAME>"/>""" , 0),
            ("""<instance/>""" , 0),
            ("""<instance/>""" , 1),
            ("""<instance/>""" , 2)
        )

        expected.zipWithIndex foreach {
            case ((expectedInnerInstanceValue, expectedNonInstanceChanges), index) ⇒
                // Dispatch event and assert result
                dispatch("update" + (index + 1), "model")

                assert(instanceToString(innerInstance) === expectedInnerInstanceValue)
                assert(nonInstanceChanges === expectedNonInstanceChanges)
        }
    }

    @Test def mirrorXBL(): Unit = {

        this setupDocument
            <xh:html xmlns:xh="http://www.w3.org/1999/xhtml"
                     xmlns:xf="http://www.w3.org/2002/xforms"
                     xmlns:ev="http://www.w3.org/2001/xml-events"
                     xmlns:xxf="http://orbeon.org/oxf/xml/xforms"
                     xmlns:xbl="http://www.w3.org/ns/xbl"<commit_msg>Following #2028: also add test to mirrorInSamePart<commit_after>/**
 * Copyright (C) 2011 Orbeon, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation; either version
 * 2.1 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * The full text of the license is available at http://www.gnu.org/copyleft/lesser.html
 */
package org.orbeon.oxf.xforms.control.controls

import XXFormsDynamicControl._
import org.junit.Test
import org.orbeon.oxf.test.DocumentTestBase
import org.orbeon.oxf.xforms.control.controls.InstanceMirror._
import org.scalatest.junit.AssertionsForJUnit
import org.orbeon.oxf.xforms.XFormsConstants.COMPONENT_SEPARATOR
import org.orbeon.oxf.xml.Dom4j.elemToDocument

class InstanceMirrorTest extends DocumentTestBase with AssertionsForJUnit {

    @Test def mirrorInSamePart(): Unit = {

        this setupDocument
            <xh:html xmlns:xh="http://www.w3.org/1999/xhtml"
                     xmlns:xf="http://www.w3.org/2002/xforms"
                     xmlns:ev="http://www.w3.org/2001/xml-events"
                     xmlns:xxf="http://orbeon.org/oxf/xml/xforms">

                <xh:head>
                    <xf:model id="model">
                        <xf:instance id="form-instance" xxf:exclude-result-prefixes="#all">
                            <xh:html>
                                <xh:head>
                                    <xf:model id="my-model">
                                        <xf:instance id="my-instance">
                                            <instance/>
                                        </xf:instance>
                                    </xf:model>
                                </xh:head>
                                <xh:body/>
                            </xh:html>
                        </xf:instance>

                        <xf:instance id="my-instance" xxf:exclude-result-prefixes="#all">
                            <instance xmlns=""/>
                        </xf:instance>

                        <xf:insert   ev:event="update1"  context="//xf:instance/instance"   origin="xf:element('first', 'Arthur')"/>
                        <xf:insert   ev:event="update2"  ref="//xf:instance/instance/first" origin="xf:element('last', 'Clark')"    position="after"/>
                        <xf:insert   ev:event="update3"  ref="//xf:instance/instance/last"  origin="xf:element('middle', 'C.')"     position="before"/>
                        <xf:setvalue ev:event="update4"  ref="//xf:instance/instance/last">Clarke</xf:setvalue>
                        <xf:insert   ev:event="update5"  ref="//xf:instance/instance/last"  origin="xf:element('last', 'Clarke!')"  position="before"/>
                        <xf:delete   ev:event="update6"  ref="//xf:instance/instance/*"/>
                        <xf:insert   ev:event="update7"  context="//xf:instance/instance"   origin="xf:attribute('first', 'Arthur')"/>
                        <xf:insert   ev:event="update8"  ref="//xf:instance/instance/@*"    origin="xf:attribute('last', 'Clarke')" position="after"/>
                        <xf:setvalue ev:event="update9"  ref="//xf:instance/instance/@last"><NAME></xf:setvalue>
                        <xf:delete   ev:event="update10"  ref="//xf:instance/instance/@*"/>
                        <xf:insert   ev:event="update11" context="/*/xh:body"               origin="xf:element('xh:div')"/>
                        <xf:setvalue ev:event="update12" ref="/*/xh:body/xh:div">Hello!</xf:setvalue>
                    </xf:model>
                </xh:head>
                <xh:body/>
            </xh:html>

        implicit val logger = document.indentedLogger

        val outerInstance = document.findInstance("form-instance").get
        val innerInstance = document.findInstance("my-instance").get

        var nonInstanceChanges = 0

        // Attach listeners
        val outerListener = {

            val unknownChange: MirrorEventListener = _ ⇒ {
                nonInstanceChanges += 1
                true
            }

            val outerMirrorListener =
                mirrorListener(
                    document,
                    toInnerInstanceNode(
                        outerInstance.documentInfo,
                        document.getStaticState.topLevelPart,
                        document,
                        findOuterInstanceDetailsDynamic
                    )
                )

            toEventListener(composeListeners(Seq(outerMirrorListener, unknownChange)))
        }

        addListener(outerInstance, outerListener)

        // Test insert, value change and delete
        val expected = Seq(
            ("""<instance><first>Arthur</first></instance>""", 0),
            ("""<instance><first>Arthur</first><last>Clark</last></instance>""" , 0),
            ("""<instance><first>Arthur</first><middle>C.</middle><last>Clark</last></instance>""" , 0),
            ("""<instance><first>Arthur</first><middle>C.</middle><last>Clarke</last></instance>""" , 0),
            ("""<instance><first>Arthur</first><middle>C.</middle><last>Clarke!</last><last>Clarke</last></instance>""" , 0),
            ("""<instance/>""" , 0),
            ("""<instance first="Arthur"/>""" , 0),
            ("""<instance first="Arthur" last="Clarke"/>""" , 0),
            ("""<instance first="Arthur" last="<NAME>"/>""" , 0),
            ("""<instance/>""" , 0),
            ("""<instance/>""" , 1),
            ("""<instance/>""" , 2)
        )

        expected.zipWithIndex foreach {
            case ((expectedInnerInstanceValue, expectedNonInstanceChanges), index) ⇒
                // Dispatch event and assert result
                dispatch("update" + (index + 1), "model")

                assert(instanceToString(innerInstance) === expectedInnerInstanceValue)
                assert(nonInstanceChanges === expectedNonInstanceChanges)
        }
    }

    @Test def mirrorXBL(): Unit = {

        this setupDocument
            <xh:html xmlns:xh="http://www.w3.org/1999/xhtml"
                     xmlns:xf="http://www.w3.org/2002/xforms"
                     xmlns:ev="http://www.w3.org/2001/xml-events"
                     xmlns:xxf="http://orbeon.org/oxf/xml/xforms"
                     xmlns:xbl="http://www.w3.org/ns/xbl"
{'fraction_non_alphanumeric': 0.14114740174503898, 'fraction_numerical': 0.010578333719403907, 'mean_word_length': 1.8004324324324323, 'pattern_counts': {'":': 0, '<': 158, '<?xml version=': 0, '>': 156, 'https://': 0, 'lorem ipsum': 0, 'www.': 16, 'xml': 30}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '142607', 'n_tokens_mistral': 3666, 'n_tokens_neox': 3415, 'n_words': 635}