<reponame>gdubicki/yamlpath
import pytest

from tests.conftest import create_temp_yaml_file, requireseyaml, old_eyaml_keys


class Test_commands_yaml_diff():
    """Tests for the yaml-diff command-line tool."""
    command = "yaml-diff"

    ###
    # Simple Hash comparisons
    ###
    lhs_hash_content = """---
key: value
hash:
  with:
    multiple: child
    key_value: pairs
  and:
    complex: structure
    with:
      several: levels
lhs_exclusive: value
"""

    rhs_hash_content = """---
key: changed value
hash:
  with:
    multiple: children
    key_value: pairs
  and:
    complex:
      more: complex
    with:
      several_nested: levels
  including:
    additional: structure
rhs_exclusive: value
"""

    ###
    # Simple Array comparisons
    ###
    lhs_array_content = """---
- alpha
- mu
- psi
- beta
- delta
- chi
- delta
- gamma
- alpha
- theta
"""

    rhs_array_content = """---
- zeta
- mu
- psi
- alpha
- gamma
- gamma
- phi
- beta
- chi
"""

    diff_array_defaults = """c [0]
< "alpha"
---
> "zeta"

c [3]
< "beta"
---
> "alpha"

c [4]
< "delta"
---
> "gamma"

c [5]
< "chi"
---
> "gamma"

c [6]
< "delta"
---
> "phi"

c [7]
< "gamma"
---
> "beta"

c [8]
< "alpha"
---
> "chi"

d [9]
< "theta"
"""


    ###
    # Simple Array-of-Hashes comparisons
    ###
    lhs_aoh_content = """---
- step: 0
  action: INITIALIZE
- step: 1
  action: input
  args:
    - world
- step: 2
  action: print
  message: Hello, %args[0]!
- step: 3
  action: quit
  status: 0
- step: 9
  action: CLEANUP
"""

    rhs_aoh_content = """---
- step: 0
  action: INITIALIZE
- step: 3
  action: quit
  status: 0
- step: 2
  action: print
  message: A tout %args[0]!
- step: 1
  action: input
  args:
    - le monde
- step: 9
  action: CLEANUP
"""

    diff_hash_defaults = """d hash.and.complex
< "structure"

c key
< "value"
---
> "changed value"

a rhs_exclusive
> "value"

d lhs_exclusive
< "value"

c hash.with.multiple
< "child"
---
> "children"

a hash.and.complex.more
> "complex"

d hash.and.with.several
< "levels"

a hash.and.with.several_nested
> "levels"

a hash.including
> {"additional": "structure"}
"""

    diff_aoh_deep = """c [3].args[0]
< "world"
---
> "le monde"

c [2].message
< "Hello, %args[0]!"
---
> "A tout %args[0]!"
"""

    ###
    # Simple Set comparisons
    ###
    lhs_set_content = """--- !!set
? one
? two
? four
"""

    rhs_set_content = """--- !!set
? four
? three
? two
"""

    diff_set_defaults = """d one
< "one"

a three
> "three"
"""

    diff_set_verbose = """d0.4.0.0.4.0 one
< "one"

a0.4.0.0.4.1 three
> "three"
"""


    def test_no_options(self, script_runner):
        result = script_runner.run(self.command)
        assert not result.success, result.stderr
        assert "the following arguments are required: YAML_FILE" in result.stderr

    def test_too_many_pseudo_files(self, script_runner):
        result = script_runner.run(self.command, "-", "-")
        assert not result.success, result.stderr
        assert "Only one YAML_FILE may be the - pseudo-file" in result.stderr

    def test_missing_first_input_file_arg(self, script_runner):
        result = script_runner.run(self.command, "no-file.yaml", "no-file.yaml")
        assert not result.success, result.stderr
        assert "File not found" in result.stderr

    def test_missing_second_input_file_arg(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        result = script_runner.run(self.command, lhs_file, "no-file.yaml")
        assert not result.success, result.stderr
        assert "File not found" in result.stderr

    def test_cannot_quiet_sameness(self, script_runner):
        result = script_runner.run(self.command, "--quiet", "--same", "any-file.yaml", "any-other-file.json")
        assert not result.success, result.stderr
        assert "The --quiet|-q option suppresses all output, including" in result.stderr

    def test_missing_config_file(self, script_runner):
        result = script_runner.run(self.command, "--config=/does/not/exist/on/most/systems.ini", "any-file.yaml", "any-other-file.json")
        assert not result.success, result.stderr
        assert "INI style configuration file is not readable" in result.stderr

    def test_missing_private_key(self, script_runner):
        result = script_runner.run(self.command, "--privatekey=/does/not/exist/on/most/systems.key", "any-file.yaml", "any-other-file.json")
        assert not result.success, result.stderr
        assert "EYAML private key is not a readable file" in result.stderr

    def test_missing_public_key(self, script_runner):
        result = script_runner.run(self.command, "--publickey=/does/not/exist/on/most/systems.key", "any-file.yaml", "any-other-file.json")
        assert not result.success, result.stderr
        assert "EYAML public key is not a readable file" in result.stderr

    def test_bad_eyaml_value(self, script_runner, tmp_path_factory):
        content = """---
        aliases:
          - &encryptedScalar >
            ENC[PKCS7,MIIx...broken-on-purpose...==]
        """
        yaml_file = create_temp_yaml_file(tmp_path_factory, content)
        result = script_runner.run(
            self.command,
            "--eyaml=/does/not/exist-on-most/systems",
            yaml_file,
            yaml_file
        )
        assert not result.success, result.stderr
        assert "No accessible eyaml command" in result.stderr

    def test_diff_yaml_parsing_error(self, script_runner, imparsible_yaml_file, badsyntax_yaml_file):
        result = script_runner.run(
            self.command,
            imparsible_yaml_file,
            badsyntax_yaml_file
        )
        assert not result.success, result.stderr
        assert "YAML parsing error" in result.stderr

    def test_multidoc_missing_lhs_index_error(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
key: value
...
---
second_key: second value
...
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)

        result = script_runner.run(
            self.command,
            lhs_file,
            rhs_file
        )
        assert not result.success, result.stderr
        assert "--left-document-index|-L must be set" in result.stderr

    def test_multidoc_missing_rhs_index_error(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
key: value
...
---
second_key: second value
...
""")

        result = script_runner.run(
            self.command,
            lhs_file,
            rhs_file
        )
        assert not result.success, result.stderr
        assert "--right-document-index|-R must be set" in result.stderr

    def test_multidoc_index_too_high(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--left-document-index=1"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert "DOCUMENT_INDEX is too high" in result.stderr

    def test_no_diff_two_hash_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert result.success, result.stderr
        assert "" == result.stdout

    def test_no_diff_two_aoh_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert result.success, result.stderr
        assert "" == result.stdout

    def test_no_hash_diff_lhs_from_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = subprocess.run(
            [self.command
            , "-"
            , rhs_file
            ]
            , stdout=subprocess.PIPE
            , input=self.lhs_hash_content
            , universal_newlines=True
        )
        assert 0 == result.returncode, result.stderr
        assert "" == result.stdout

    def test_no_aoh_diff_lhs_from_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = subprocess.run(
            [self.command
            , "-"
            , rhs_file
            ]
            , stdout=subprocess.PIPE
            , input=self.lhs_aoh_content
            , universal_newlines=True
        )
        assert 0 == result.returncode, result.stderr
        assert "" == result.stdout

    def test_no_hash_diff_rhs_from_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_hash_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = subprocess.run(
            [self.command
            , lhs_file
            , "-"
            ]
            , stdout=subprocess.PIPE
            , input=self.rhs_hash_content
            , universal_newlines=True
        )
        assert 0 == result.returncode, result.stderr
        assert "" == result.stdout

    def test_no_aoh_diff_rhs_from_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = subprocess.run(
            [self.command
            , lhs_file
            , "-"
            ]
            , stdout=subprocess.PIPE
            , input=self.rhs_aoh_content
            , universal_newlines=True
        )
        assert 0 == result.returncode, result.stderr
        assert "" == result.stdout

    def test_quiet_diff_two_hash_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_hash_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--quiet"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert "" == result.stdout

    def test_simple_diff_two_hash_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_hash_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert self.diff_hash_defaults == result.stdout

    def test_default_diff_two_aoh_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)
        stdout_content = """c [1]
< {"step": 1, "action": "input", "args": ["world"]}
---
> {"step": 3, "action": "quit", "status": 0}

c [2]
< {"step": 2, "action": "print", "message": "Hello, %args[0]!"}
---
> {"step": 2, "action": "print", "message": "A tout %args[0]!"}

c [3]
< {"step": 3, "action": "quit", "status": 0}
---
> {"step": 1, "action": "input", "args": ["le monde"]}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_position_diff_two_aoh_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)
        stdout_content = """c [1]
< {"step": 1, "action": "input", "args": ["world"]}
---
> {"step": 3, "action": "quit", "status": 0}

c [2]
< {"step": 2, "action": "print", "message": "Hello, %args[0]!"}
---
> {"step": 2, "action": "print", "message": "A tout %args[0]!"}

c [3]
< {"step": 3, "action": "quit", "status": 0}
---
> {"step": 1, "action": "input", "args": ["le monde"]}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--aoh=position"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_key_diff_two_aoh_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)
        stdout_content = """c [1]
< {"step": 1, "action": "input", "args": ["world"]}
---
> {"step": 1, "action": "input", "args": ["le monde"]}

c [2]
< {"step": 2, "action": "print", "message": "Hello, %args[0]!"}
---
> {"step": 2, "action": "print", "message": "A tout %args[0]!"}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--aoh=key"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_dpos_diff_two_aoh_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)
        stdout_content = """c [1].step
< 1
---
> 3

a [1].status
> 0

c [1].action
< "input"
---
> "quit"

d [1].args
< ["world"]

c [2].message
< "Hello, %args[0]!"
---
> "A tout %args[0]!"

c [3].step
< 3
---
> 1

c [3].action
< "quit"
---
> "input"

d [3].status
< 0

a [3].args
> ["le monde"]
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--aoh=dpos"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_deep_diff_two_aoh_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--aoh=deep"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert self.diff_aoh_deep == result.stdout

    def test_value_diff_two_aoh_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)
        stdout_content = """d [1]
< {"step": 1, "action": "input", "args": ["world"]}

c [2]
< {"step": 2, "action": "print", "message": "Hello, %args[0]!"}
---
> {"step": 2, "action": "print", "message": "A tout %args[0]!"}

a [3]
> {"step": 1, "action": "input", "args": ["le monde"]}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--aoh=value"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_simple_hash_diff_lhs_from_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_hash_content)

        result = subprocess.run(
            [self.command
            , "-"
            , rhs_file
            ]
            , stdout=subprocess.PIPE
            , input=self.lhs_hash_content
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert self.diff_hash_defaults == result.stdout

    def test_simple_aoh_diff_lhs_from_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)

        result = subprocess.run(
            [self.command
            , "--aoh=deep"
            , "-"
            , rhs_file
            ]
            , stdout=subprocess.PIPE
            , input=self.lhs_aoh_content
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert self.diff_aoh_deep == result.stdout

    def test_simple_hash_diff_rhs_from_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)

        result = subprocess.run(
            [self.command
            , lhs_file
            , "-"
            ]
            , stdout=subprocess.PIPE
            , input=self.rhs_hash_content
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert self.diff_hash_defaults == result.stdout

    def test_simple_aoh_diff_rhs_from_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)

        result = subprocess.run(
            [self.command
            , "--aoh=deep"
            , lhs_file
            , "-"
            ]
            , stdout=subprocess.PIPE
            , input=self.rhs_aoh_content
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert self.diff_aoh_deep == result.stdout

    def test_simple_diff_hash_from_nothing_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_hash_content)
        stdout_content = """a key
> "changed value"

a rhs_exclusive
> "value"

a hash
> {"with": {"multiple": "children", "key_value": "pairs"}, "and": {"complex": {"more": "complex"}, "with": {"several_nested": "levels"}}, "including": {"additional": "structure"}}
"""

        result = subprocess.run(
            [self.command
            , "-"
            , rhs_file
            ]
            , stdout=subprocess.PIPE
            , input=""
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout

    def test_simple_diff_aoh_from_nothing_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)
        stdout_content = """a [0]
> {"step": 0, "action": "INITIALIZE"}

a [1]
> {"step": 3, "action": "quit", "status": 0}

a [2]
> {"step": 2, "action": "print", "message": "A tout %args[0]!"}

a [3]
> {"step": 1, "action": "input", "args": ["le monde"]}

a [4]
> {"step": 9, "action": "CLEANUP"}
"""

        result = subprocess.run(
            [self.command
            , "-"
            , rhs_file
            ]
            , stdout=subprocess.PIPE
            , input=""
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout

    def test_simple_diff_hash_from_text_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_hash_content)
        stdout_content = """d -
< "This is a general text file."

a key
> "changed value"

a rhs_exclusive
> "value"

a hash
> {"with": {"multiple": "children", "key_value": "pairs"}, "and": {"complex": {"more": "complex"}, "with": {"several_nested": "levels"}}, "including": {"additional": "structure"}}
"""

        result = subprocess.run(
            [self.command
            , "-"
            , rhs_file
            ]
            , stdout=subprocess.PIPE
            , input="This is a general text file."
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout

    def test_simple_diff_aoh_from_text_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)
        stdout_content = """d -
< "This is a general text file."

a [0]
> {"step": 0, "action": "INITIALIZE"}

a [1]
> {"step": 3, "action": "quit", "status": 0}

a [2]
> {"step": 2, "action": "print", "message": "A tout %args[0]!"}

a [3]
> {"step": 1, "action": "input", "args": ["le monde"]}

a [4]
> {"step": 9, "action": "CLEANUP"}
"""

        result = subprocess.run(
            [self.command
            , "-"
            , rhs_file
            ]
            , stdout=subprocess.PIPE
            , input="This is a general text file."
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout

    def test_simple_diff_hash_into_nothing_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        stdout_content = """d key
< "value"

d lhs_exclusive
< "value"

d hash
< {"with": {"multiple": "child", "key_value": "pairs"}, "and": {"complex": "structure", "with": {"several": "levels"}}}
"""

        result = subprocess.run(
            [self.command
            , lhs_file
            , "-"
            ]
            , stdout=subprocess.PIPE
            , input=""
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout

    def test_simple_diff_aoh_into_nothing_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        stdout_content = """d [0]
< {"step": 0, "action": "INITIALIZE"}

d [1]
< {"step": 1, "action": "input", "args": ["world"]}

d [2]
< {"step": 2, "action": "print", "message": "Hello, %args[0]!"}

d [3]
< {"step": 3, "action": "quit", "status": 0}

d [4]
< {"step": 9, "action": "CLEANUP"}
"""

        result = subprocess.run(
            [self.command
            , lhs_file
            , "-"
            ]
            , stdout=subprocess.PIPE
            , input=""
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout

    def test_simple_diff_hash_into_text_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        stdout_content = """a -
> "This is a general text file."

d key
< "value"

d lhs_exclusive
< "value"

d hash
< {"with": {"multiple": "child", "key_value": "pairs"}, "and": {"complex": "structure", "with": {"several": "levels"}}}
"""

        result = subprocess.run(
            [self.command
            , lhs_file
            , "-"
            ]
            , stdout=subprocess.PIPE
            , input="This is a general text file."
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout

    def test_simple_diff_aoh_into_text_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        stdout_content = """a -
> "This is a general text file."

d [0]
< {"step": 0, "action": "INITIALIZE"}

d [1]
< {"step": 1, "action": "input", "args": ["world"]}

d [2]
< {"step": 2, "action": "print", "message": "Hello, %args[0]!"}

d [3]
< {"step": 3, "action": "quit", "status": 0}

d [4]
< {"step": 9, "action": "CLEANUP"}
"""

        result = subprocess.run(
            [self.command
            , lhs_file
            , "-"
            ]
            , stdout=subprocess.PIPE
            , input="This is a general text file."
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout

    def test_onlysame_diff_two_hash_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_hash_content)
        stdout_content = """s hash.with.key_value
= "pairs"
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--onlysame"
            , "--aoh=deep"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_onlysame_deep_diff_two_aoh_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)
        stdout_content = """s [0].step
= 0

s [0].action
= "INITIALIZE"

s [3].step
= 1

s [3].action
= "input"

s [2].step
= 2

s [2].action
= "print"

s [1].step
= 3

s [1].action
= "quit"

s [1].status
= 0

s [4].step
= 9

s [4].action
= "CLEANUP"
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--onlysame"
            , "--aoh=deep"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_two_aliased_hash_files(self, script_runner, tmp_path_factory):
        """
        Test Anchors, their Aliases, and YAML Merge Operators.

        Also demonstrate that the yaml-diff tool is a FUNCTIONAL comparison of
        two data files, NOT a textual comparison.  In other words, yaml-diff is
        only interested in how the data is represented to YAML/JSON parsers,
        NOT how the YAML/JSON file is constructed.  Immaterial elements like
        comments, white-space, and demarcation symbols are deliberately ignored
        because none of these have any impact on what data YAML/JSON parsers
        actually percieve to be within the files at run-time.

        Users who need a TEXTUAL (non-functional) comparison of two YAML/JSON
        files should use the GNU `diff` command-line tool rather than this
        yaml-diff command-line tool.
        """
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
aliases:
  - &string_value This is a reusable string value.
  - &int_value 5280
some_values: &some_values
  aliased_int: *int_value
  original_float: 3.14159265358
more_values: &more_values
  aliased_string: *string_value
  original_string: This is another reusable string except its in a reusable parent Hash.
collector_hash:
  <<: [ *some_values, *more_values ]
  concrete_string: This is a non-reusable concrete string.
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
# Reusable aliases
aliases:
  - &string_value This is a CHANGED reusable string value.
  - &aliased_int_value 5280

# Reusable numbers reusing one number
some_values: &some_values
  aliased_int: *aliased_int_value
  original_float: 3.14

# Reusable strings reusing one string
more_values: &more_values
  aliased_string: *string_value
  original_string: "This is another reusable string except its in a reusable parent Hash."

# Bring it all together
collector_hash:
  <<: [ *some_values, *more_values ]
  concrete_string: 'This is a non-reusable concrete string.'
""")
        stdout_content = """c aliases[0]
< "This is a reusable string value."
---
> "This is a CHANGED reusable string value."

c some_values.original_float
< 3.14159265358
---
> 3.14

c more_values.aliased_string
< "This is a reusable string value."
---
> "This is a CHANGED reusable string value."

c collector_hash.original_float
< 3.14159265358
---
> 3.14

c collector_hash.aliased_string
< "This is a reusable string value."
---
> "This is a CHANGED reusable string value."
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_simple_diff_two_hash_files_fslash(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_hash_content)
        stdout_content = """d /hash/and/complex
< "structure"

c /key
< "value"
---
> "changed value"

a /rhs_exclusive
> "value"

d /lhs_exclusive
< "value"

c /hash/with/multiple
< "child"
---
> "children"

a /hash/and/complex/more
> "complex"

d /hash/and/with/several
< "levels"

a /hash/and/with/several_nested
> "levels"

a /hash/including
> {"additional": "structure"}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--pathsep=/"
            , "--aoh=deep"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    @requireseyaml
    def test_diff_eyaml_allowed(self, script_runner, tmp_path_factory, old_eyaml_keys):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
same_secret_same_crypt: >-
  <KEY>/NSVF5NEeTz
  MvIW862oA8UFtodj]
same_secret_different_crypt: >-
  ENC[<KEY>
  <KEY>
  <KEY>
  <KEY>
  rg/XOLJXzkkyKEoKIFScBT115aedGY60baMtvD1Md9rxi97xCmj6BroatMlM
  Cm266oFnijrQN9Xsb5ZTnGiPMA9hC2y6X+oJeMaG0S6G64EnTwnjAQytWE6a
  J<KEY>yO70RwACV9QknSqoLuUbYpcbU4FHU/xICiWAG
  <KEY>
  R<KEY>
  W<KEY>
  nNuWarGVGx1Bv+6h]
different_secrets: >-
  ENC[PKCS7,<KEY>MAACAQEw
  DQYJKoZIhvcNAQEBBQAEggEAJRw+urxm+Pyt0Xys5UpJUIaZhA0Tt1JuVsLG
  9jiHb9aua+2bBr/kAN8D/+dowOJlVkG6LZ4Uzn+NZboO8Q2JpQeV9CJTqayJ
  eZnRx02298qSrWOogSQUoS/<KEY>
  gAgL5bAXzD2+1MHIRMrf8ascVmTOV4/JMckWznCseM+uJ7PkR12044mWhuvk
  aJUjaXFXIEYhA4+jjKWdlOTWJ<KEY>aNZVlcf8X1WuoX4f1iPP53z
  mATu0eDx8D5XwQnygUMrPWrlCyoIqRIcwU6f5iv+HT1EWEvSI5+i7bByx0hk
  apUR+TBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBCgVC5h5pznSfACl7+Q
  ff+mgDBAZPMofXWfguD6OgcXu0/QMz90QHAN4bu+CHHZLZ+8X3qSgKHszijK
  eEeStAMoq50=]
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
same_secret_same_crypt: >-
  ENC[PKCS7,MIIBygYJKoZIhvcNAQcDoIIBuzCCAbcCAQAxggEhMIIBHQIBADAFMAACAQEw
  DQYJKoZIhvcNAQEBBQAEggEAP5tXc8gPp1p5945Ih/i/k/OqvoDrWi/F05/V
  EhlgUwXgNer0Y5C7G/FE4Gt5nasoolbPQTMVuq+CW8qQ6wsnVrB60SCDvy5q
  <KEY>]
same_secret_different_crypt: >-
  ENC[PKCS7,MIIBygYJKoZIhvcNAQcDoIIBuzCCAbcCAQAxggEhMIIBHQIBADAFMAACAQEw
  DQYJKoZIhvcNAQEBBQAEggEAV/S/jxC79aiKR1UnPxcrPo7bLpSpsoUqJfdQ
  znMp0LJrqacIcrq+jFRLqFUv2dDcTRnReP5CZy4HEJw73710Ngb+sJLQeCE9
  f8qYvjKAlWyrw0Strpwe5BQT4g7ph5GX3lOqjCBJbqRPE9XfhI9DPljkUzBB
  IQ8zVZz/zy5TbBCRZm7RKPjbczTMaHRRQb0fEKnK7tTdHIucNRQh0AZ9ZGuJ
  8TchxlBhgtwjKU0NxbpQyi/hVyv7Dw8/wSq3Wp5nFYJj1uFxYES0sw6QAsM+
  1LzY2hg+RCzL3gxU724gH0xRCv346tKoyqzVxtO+knLVh/m8HulrXJABKn0/
  ZJrBezCBjAYJKoZIhvcNAQcBMB0GCWCGSAFlAwQBKgQQMvmLomzj48fPsA1H
  DVQiaoBgctgTfmmKEaEoCYJqd4WXpJeb96viMyTXRaa8Pt0rl22mbt92qMUk
  witfhD7lzteg1k2tunXQx8w37vx60kqY3aEXV8crQb1TQdBUuZIks1RnLFur
  14/eAgRAn37NhJli]
different_secrets: >-
  ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEw
  DQYJKoZIhvcNAQEBBQAEggEAm9Sw3jUCLMOKU0wpQgu7kW4yO/MvoLbQpWMB
  KKFEssxhJ0Kqc5Q+2cTAk6vo5K7GopVYr5iCaaoxLmCJq3ke1XBR6O182q/2
  vcvgqTVq3OaaMR3qji1edJQd6NJuqpuV+tIf6RCktt5+9wlIXLxujnaYxmr1
  vrEMXnb0R6PWunXsTAlDDrCVMC6iXIvbhsP2GF8zhhuTkCXp1LTDuvj3aSso
  iloELuCdCGO7iFTXPuPy4nrgXjlaVnGftoDmVukDP8PUzyEBT1a9ZXUjrswS
  sXzCsTnEGIpPlIe84Nvk43osbVw2sOgwod7Uko7KmdXVFAh8l15BoW5E9uRw
  y2XahTBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBAIA2FJ1Fo38jwnbHs8
  V8GOgDAaCmR9jyjK/0f0V2WnRF+nPS21sNoB0qONn1V0GwAQbu0yk7QS5y8q
  4OTZEGxziGU=]
""")
        stdout_content = """c different_secrets
< "ENC[PKCS7,<KEY>=]"
---
> "ENC[<KEY>
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--privatekey={}".format(old_eyaml_keys[0])
            , "--publickey={}".format(old_eyaml_keys[1])
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_eyaml_disallowed(self, script_runner, tmp_path_factory, old_eyaml_keys):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
same_secret_same_crypt: >
  ENC[PKCS7,<KEY>
  MvIW862oA8UFtodj]
same_secret_different_crypt: >
  ENC[PKCS7,<KEY>]
different_secrets: >
  <KEY>
  ff+<KEY>
  eEeStAMoq50=]
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
same_secret_same_crypt: >
  ENC[PKCS7,MIIBygYJKoZIhvcNAQcDoIIBuzCCAbcCAQAxggEhMIIBHQIBADAFMAACAQEw
  DQYJKoZIhvcNAQEBBQAEggEAP5tXc8gPp1p5945Ih/i/k/OqvoDrWi/F05/V
  EhlgUwXgNer0Y5C7G/FE4Gt5nasoolbPQTMVuq+CW8qQ6wsnVrB60SCDvy5q
  9k7WGHyQU5n6UR00/RLhctStGe6nN/zIsoYLQyyY/+xJaHAwahB/GkzFPk9S
  <KEY>]
same_secret_different_crypt: >
  <KEY>
  <KEY>]
different_secrets: >
  <KEY>UDBAEqBBAIA2FJ1Fo38jwnbHs8
  V8GOgDAaCmR9jyjK/0f0V2WnRF+nPS21sNoB0qONn1V0GwAQbu0yk7QS5y8q
  4OTZEGxziGU=]
""")
        stdout_content = """c same_secret_different_crypt
< "ENC[PKCS7,MIIBygYJKoZIhvcNAQcDoIIBuzCCAbcCAQAxggEhMIIBHQIBADAFMAACAQEw DQYJKoZIhvcNAQEBBQAEggEAYUDg4y4+LXY0IdEDYFgxfxRJ3dfkOPwTSLxl A91x5IQlgQYQpXkgkFEeJj3EXdYwt9K6prtFywokVQoOaWgXWWV+Tf0lF5P0 0sw4LH7MgaszKPpiOHxx9hTmexEIusF+tzvQBOD1zHfDdkZQ0v9R3JLHckub rg/XOLJXzkkyKEoKIFScBT115aedGY60baMtvD1Md9rxi97xCmj6BroatMlM Cm266oFnijrQN9Xsb5ZTnGiPMA9hC2y6X+oJeMaG0S6G64EnTwnjAQytWE6a JM1/YXVKIoE2c/E44/m74kuyO70RwACV9QknSqoLuUbYpcbU4FHU/xICiWAG CaTz9zCBjAYJKoZIhvcNAQcBMB0GCWCGSAFlAwQBKgQQ9kFVNmG9heK0WyWU R1kfyIBgCIJzi+XnQMS9w85Mbq6BaNPpJrU7ZaoHQ6c3Ps9sgJStVDQNmrbL WAP8fEC6S7V07rA7hp4YomvAJRJjDIK7M2AzXDNzupuAh4crF905AR4TF+Jd nNuWarGVGx1Bv+6h]"
---
> "<KEY>

c different_secrets
< "<KEY>]"
---
> "ENC[<KEY>
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--ignore-eyaml-values"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_two_multiline_string_hash_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
folded_string: >
  This is
  one really long
  string.  It
  is presented in
  YAML "folded"
  format.  This will
  cause all of the
  new-line characters
  to be replaced with
  single spaces
  when this value
  is read by a
  YAML parser.

literal_string: |
  This is another
  really long string.
  It is presented in
  YAML "literal"
  format.  When a
  YAML parser reads
  this value, all of
  these new-line
  characters will be
  preserved.
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
folded_string: >
  This CHANGED
  one really long
  string.  It
  is presented in
  YAML "folded"
  format.  This will
  cause all of the
  new-line characters
  to be replaced with
  single spaces
  when this value
  is read by a
  YAML parser.

literal_string: |
  This is another
  really long CHANGED string.
  It is presented in
  YAML "literal"
  format.  When a
  YAML parser reads
  this value, all of
  these new-line
  characters will be
  preserved.
""")
        stdout_content = r"""c folded_string
< "This is one really long string.  It is presented in YAML \"folded\" format.  This will cause all of the new-line characters to be replaced with single spaces when this value is read by a YAML parser."
---
> "This CHANGED one really long string.  It is presented in YAML \"folded\" format.  This will cause all of the new-line characters to be replaced with single spaces when this value is read by a YAML parser."

c literal_string
< "This is another
< really long string.
< It is presented in
< YAML \"literal\"
< format.  When a
< YAML parser reads
< this value, all of
< these new-line
< characters will be
< preserved."
---
> "This is another
> really long CHANGED string.
> It is presented in
> YAML \"literal\"
> format.  When a
> YAML parser reads
> this value, all of
> these new-line
> characters will be
> preserved."
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_two_multiline_string_hash_files_verbosely(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
folded_string: >
  This is
  one really long
  string.  It
  is presented in
  YAML "folded"
  format.  This will
  cause all of the
  new-line characters
  to be replaced with
  single spaces
  when this value
  is read by a
  YAML parser.

literal_string: |
  This is another
  really long string.
  It is presented in
  YAML "literal"
  format.  When a
  YAML parser reads
  this value, all of
  these new-line
  characters will be
  preserved.
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
folded_string: >
  This CHANGED
  one really long
  string.  It
  is presented in
  YAML "folded"
  format.  This will
  cause all of the
  new-line characters
  to be replaced with
  single spaces
  when this value
  is read by a
  YAML parser.

literal_string: |
  This is another
  really long CHANGED string.
  It is presented in
  YAML "literal"
  format.  When a
  YAML parser reads
  this value, all of
  these new-line
  characters will be
  preserved.
""")
        stdout_content = r"""c1.0.0.1.0.0 folded_string
< "This is one really long string.  It is presented in YAML \"folded\" format.  This will cause all of the new-line characters to be replaced with single spaces when this value is read by a YAML parser."
---
> "This CHANGED one really long string.  It is presented in YAML \"folded\" format.  This will cause all of the new-line characters to be replaced with single spaces when this value is read by a YAML parser."

c1.0.1.1.0.1 literal_string
< "This is another
< really long string.
< It is presented in
< YAML \"literal\"
< format.  When a
< YAML parser reads
< this value, all of
< these new-line
< characters will be
< preserved."
---
> "This is another
> really long CHANGED string.
> It is presented in
> YAML \"literal\"
> format.  When a
> YAML parser reads
> this value, all of
> these new-line
> characters will be
> preserved."
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--verbose"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_array_by_default(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_array_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_array_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert self.diff_array_defaults == result.stdout

    def test_diff_array_by_position(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_array_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_array_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--arrays=position"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert self.diff_array_defaults == result.stdout

    def test_diff_array_by_value(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_array_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_array_content)
        stdout_content = """a [0]
> "zeta"

a [5]
> "gamma"

c [6]
< "delta"
---
> "phi"

d [4]
< "delta"

d [8]
< "alpha"

d [9]
< "theta"
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--arrays=value"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_add_array_element(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
- 0
- 1
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
- 0
- 1
- 2
""")
        stdout_content = """a [2]
> 2
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_add_aoh_element_default(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 0
  name: zero
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 0
  name: zero
- id: 1
  name: uno
""")
        stdout_content = """a [1]
> {"id": 1, "name": "uno"}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_add_aoh_element_key(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 1
  name: uno
- id: 0
  name: zero
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 0
  name: zero
- id: 2
  name: dos
- id: 1
  name: uno
""")
        stdout_content = """a [1]
> {"id": 2, "name": "dos"}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--aoh=key"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_delete_aoh_element_default(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 0
  name: zero
- id: 1
  name: uno
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 0
  name: zero
""")
        stdout_content = """d [1]
< {"id": 1, "name": "uno"}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_delete_aoh_element_key(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 0
  name: zero
- id: 1
  name: uno
- id: 2
  name: dos
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 1
  name: uno
- id: 0
  name: zero
""")
        stdout_content = """d [2]
< {"id": 2, "name": "dos"}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--aoh=key"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_unkeyed_aoh_elements(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 1
  name: uno
- id: 0
  name: zero
- name: tres
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 0
  name: zero
- name: dos
- id: 1
  name: uno
""")
        stdout_content = """a [1]
> {"name": "dos"}

d [2]
< {"name": "tres"}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--aoh=key"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_custom_aoh_keyed_elements(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
products:
  - product: doodad
    sku: 0-000-0001-0
    availability:
      start:
        date: 2020-10-10
        time: 08:00
      stop:
        date: 2020-10-29
        time: 17:00
    dimensions:
      width: 5
      height: 5
      depth: 5
      weight: 10
  - product: dumdow
    sku: 0-000-0002-0
    availability:
      start:
        date: 2020-10-23
        time: 08:00
      stop:
        date: 2020-11-23
        time: 17:00
    dimensions:
      width: 3
      height: 3
      depth: 3
      weight: 27
  - product: doohickey
    sku: 0-000-0003-0
    availability:
      start:
        date: 2020-08-01
        time: 10:00
      stop:
        date: 2020-09-25
        time: 10:00
    dimensions:
      width: 1
      height: 2
      depth: 3
      weight: 4
  - product: widget
    sku: 0-000-0004-0
    availability:
      start:
        date: 2020-01-01
        time: 12:00
      stop:
        date: 2020-01-01
        time: 16:00
    dimensions:
      width: 9
      height: 10
      depth: 1
      weight: 4
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
products:
  - sku: 0-000-0001-0
    availability:
      start:
        date: 2020-10-10
        time: 08:00
      stop:
        date: 2020-10-29
        time: 17:00
    dimensions:
      width: 5
      height: 5
      depth: 5
      weight: 10
  - sku: 0-000-0002-0
    availability:
      start:
        date: 2020-10-23
        time: 08:00
      stop:
        date: 2020-11-23
        time: 17:00
    dimensions:
      width: 4
      height: 3
      depth: 3
      weight: 27
  - dimensions:
      width: 9
      height: 10
      depth: 1
      weight: 4
    sku: 0-000-0004-0
    availability:
      start:
        date: 2020-01-01
        time: 12:00
      stop:
        date: 2020-01-01
        time: 16:00
  - product: doohickey
    availability:
      stop:
        date: 2020-09-25
        time: 10:00
      start:
        date: 2020-08-01
        time: 10:00
    dimensions:
      weight: 4
      width: 1
      depth: 3
      height: 2
""")
        config_file = create_temp_yaml_file(tmp_path_factory, """[rules]
/products = key

[keys]
/products[product=doohickey] = product
""")
        stdout_content = """c products[0]
< {"product": "doodad", "sku": "0-000-0001-0", "availability": {"start": {"date": "2020-10-10", "time": "08:00"}, "stop": {"date": "2020-10-29", "time": "17:00"}}, "dimensions": {"width": 5, "height": 5, "depth": 5, "weight": 10}}
---
> {"sku": "0-000-0001-0", "availability": {"start": {"date": "2020-10-10", "time": "08:00"}, "stop": {"date": "2020-10-29", "time": "17:00"}}, "dimensions": {"width": 5, "height": 5, "depth": 5, "weight": 10}}

c products[1]
< {"product": "dumdow", "sku": "0-000-0002-0", "availability": {"start": {"date": "2020-10-23", "time": "08:00"}, "stop": {"date": "2020-11-23", "time": "17:00"}}, "dimensions": {"width": 3, "height": 3, "depth": 3, "weight": 27}}
---
> {"sku": "0-000-0002-0", "availability": {"start": {"date": "2020-10-23", "time": "08:00"}, "stop": {"date": "2020-11-23", "time": "17:00"}}, "dimensions": {"width": 4, "height": 3, "depth": 3, "weight": 27}}

c products[2]
< {"product": "doohickey", "sku": "0-000-0003-0", "availability": {"start": {"date": "2020-08-01", "time": "10:00"}, "stop": {"date": "2020-09-25", "time": "10:00"}}, "dimensions": {"width": 1, "height": 2, "depth": 3, "weight": 4}}
---
> {"product": "doohickey", "availability": {"stop": {"date": "2020-09-25", "time": "10:00"}, "start": {"date": "2020-08-01", "time": "10:00"}}, "dimensions": {"weight": 4, "width": 1, "depth": 3, "height": 2}}

c products[3]
< {"product": "widget", "sku": "0-000-0004-0", "availability": {"start": {"date": "2020-01-01", "time": "12:00"}, "stop": {"date": "2020-01-01", "time": "16:00"}}, "dimensions": {"width": 9, "height": 10, "depth": 1, "weight": 4}}
---
> {"dimensions": {"width": 9, "height": 10, "depth": 1, "weight": 4}, "sku": "0-000-0004-0", "availability": {"start": {"date": "2020-01-01", "time": "12:00"}, "stop": {"date": "2020-01-01", "time": "16:00"}}}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--config={}".format(config_file)
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_comprehensive_tag_diffs(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
aliases:
  - &one One
  - &two !tag_two Two
  - &three !tag_three Three

hash_one:
  key_one: *one
  key_two: *two
  key_three: *three
  *one : *two
  *two : *one
  *three : *three

hash_two:
  key_one: *one
  key_two: *two
  *one : *two
  *two : *one
  *three : *three
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
aliases:
  - &one !tag_one One
  - &two Two
  - &three !tag_tres Three

hash_one:
  key_one: *one
  key_two: *two
  key_three: *three
  *one : *two
  *two : *one
  *three : *three

hash_two: !example
  key_one: *one
  key_two: *two
  *one : *two
  *two : *one
  *three : *three
""")
        stdout_content = """c aliases[0]
< "One"
---
> !tag_one "One"

c aliases[1]
< !tag_two "Two"
---
> "Two"

c aliases[2]
< !tag_three "Three"
---
> !tag_tres "Three"

c hash_one.key_one
< "One"
---
> !tag_one "One"

a hash_one.One !tag_one
> "Two"

a hash_one.Two
> !tag_one "One"

a hash_one.Three !tag_tres
> !tag_tres "Three"

c hash_one.key_two
< !tag_two "Two"
---
> "Two"

c hash_one.key_three
< !tag_three "Three"
---
> !tag_tres "Three"

d hash_one.One
< !tag_two "Two"

d hash_one.Two !tag_two
< "One"

d hash_one.Three !tag_three
< !tag_three "Three"

a hash_two !example
> {"key_one": "One", "key_two": "Two", "One": "Two", "Two": "One", "Three": "Three"}

d hash_two
< {"key_one": "One", "key_two": "Two", "One": "Two", "Two": "One", "Three": "Three"}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout


    def test_diff_set_normal(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_set_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_set_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(self.diff_set_defaults)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert self.diff_set_defaults == result.stdout

    def test_diff_set_verbose(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_set_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_set_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(self.diff_set_defaults)

        result = script_runner.run(
            self.command
            , "--verbose"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert self.diff_set_verbose == result.stdout

    def test_simple_diff_set_from_nothing_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_set_content)
        stdout_content = """a four
> "four"

a three
> "three"

a two
> "two"
"""

        result = subprocess.run(
            [self.command
            , "-"
            , rhs_file
            ]
            , stdout=subprocess.PIPE
            , input=""
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout

    def test_simple_diff_set_into_nothing_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_set_content)
        stdout_content = """d one
< "one"

d two
< "two"

d four
< "four"
"""

        result = subprocess.run(
            [self.command
            , lhs_file
            , "-"
            ]
            , stdout=subprocess.PIPE
            , input=""
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout

import pytest

from tests.conftest import create_temp_yaml_file, requireseyaml, old_eyaml_keys


class Test_commands_yaml_diff():
    """Tests for the yaml-diff command-line tool."""
    command = "yaml-diff"

    ###
    # Simple Hash comparisons
    ###
    lhs_hash_content = """---
key: value
hash:
  with:
    multiple: child
    key_value: pairs
  and:
    complex: structure
    with:
      several: levels
lhs_exclusive: value
"""

    rhs_hash_content = """---
key: changed value
hash:
  with:
    multiple: children
    key_value: pairs
  and:
    complex:
      more: complex
    with:
      several_nested: levels
  including:
    additional: structure
rhs_exclusive: value
"""

    ###
    # Simple Array comparisons
    ###
    lhs_array_content = """---
- alpha
- mu
- psi
- beta
- delta
- chi
- delta
- gamma
- alpha
- theta
"""

    rhs_array_content = """---
- zeta
- mu
- psi
- alpha
- gamma
- gamma
- phi
- beta
- chi
"""

    diff_array_defaults = """c [0]
< "alpha"
---
> "zeta"

c [3]
< "beta"
---
> "alpha"

c [4]
< "delta"
---
> "gamma"

c [5]
< "chi"
---
> "gamma"

c [6]
< "delta"
---
> "phi"

c [7]
< "gamma"
---
> "beta"

c [8]
< "alpha"
---
> "chi"

d [9]
< "theta"
"""


    ###
    # Simple Array-of-Hashes comparisons
    ###
    lhs_aoh_content = """---
- step: 0
  action: INITIALIZE
- step: 1
  action: input
  args:
    - world
- step: 2
  action: print
  message: Hello, %args[0]!
- step: 3
  action: quit
  status: 0
- step: 9
  action: CLEANUP
"""

    rhs_aoh_content = """---
- step: 0
  action: INITIALIZE
- step: 3
  action: quit
  status: 0
- step: 2
  action: print
  message: A tout %args[0]!
- step: 1
  action: input
  args:
    - le monde
- step: 9
  action: CLEANUP
"""

    diff_hash_defaults = """d hash.and.complex
< "structure"

c key
< "value"
---
> "changed value"

a rhs_exclusive
> "value"

d lhs_exclusive
< "value"

c hash.with.multiple
< "child"
---
> "children"

a hash.and.complex.more
> "complex"

d hash.and.with.several
< "levels"

a hash.and.with.several_nested
> "levels"

a hash.including
> {"additional": "structure"}
"""

    diff_aoh_deep = """c [3].args[0]
< "world"
---
> "le monde"

c [2].message
< "Hello, %args[0]!"
---
> "A tout %args[0]!"
"""

    ###
    # Simple Set comparisons
    ###
    lhs_set_content = """--- !!set
? one
? two
? four
"""

    rhs_set_content = """--- !!set
? four
? three
? two
"""

    diff_set_defaults = """d one
< "one"

a three
> "three"
"""

    diff_set_verbose = """d0.4.0.0.4.0 one
< "one"

a0.4.0.0.4.1 three
> "three"
"""


    def test_no_options(self, script_runner):
        result = script_runner.run(self.command)
        assert not result.success, result.stderr
        assert "the following arguments are required: YAML_FILE" in result.stderr

    def test_too_many_pseudo_files(self, script_runner):
        result = script_runner.run(self.command, "-", "-")
        assert not result.success, result.stderr
        assert "Only one YAML_FILE may be the - pseudo-file" in result.stderr

    def test_missing_first_input_file_arg(self, script_runner):
        result = script_runner.run(self.command, "no-file.yaml", "no-file.yaml")
        assert not result.success, result.stderr
        assert "File not found" in result.stderr

    def test_missing_second_input_file_arg(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        result = script_runner.run(self.command, lhs_file, "no-file.yaml")
        assert not result.success, result.stderr
        assert "File not found" in result.stderr

    def test_cannot_quiet_sameness(self, script_runner):
        result = script_runner.run(self.command, "--quiet", "--same", "any-file.yaml", "any-other-file.json")
        assert not result.success, result.stderr
        assert "The --quiet|-q option suppresses all output, including" in result.stderr

    def test_missing_config_file(self, script_runner):
        result = script_runner.run(self.command, "--config=/does/not/exist/on/most/systems.ini", "any-file.yaml", "any-other-file.json")
        assert not result.success, result.stderr
        assert "INI style configuration file is not readable" in result.stderr

    def test_missing_private_key(self, script_runner):
        result = script_runner.run(self.command, "--privatekey=/does/not/exist/on/most/systems.key", "any-file.yaml", "any-other-file.json")
        assert not result.success, result.stderr
        assert "EYAML private key is not a readable file" in result.stderr

    def test_missing_public_key(self, script_runner):
        result = script_runner.run(self.command, "--publickey=/does/not/exist/on/most/systems.key", "any-file.yaml", "any-other-file.json")
        assert not result.success, result.stderr
        assert "EYAML public key is not a readable file" in result.stderr

    def test_bad_eyaml_value(self, script_runner, tmp_path_factory):
        content = """---
        aliases:
          - &encryptedScalar >
            ENC[PKCS7,MIIx...broken-on-purpose...==]
        """
        yaml_file = create_temp_yaml_file(tmp_path_factory, content)
        result = script_runner.run(
            self.command,
            "--eyaml=/does/not/exist-on-most/systems",
            yaml_file,
            yaml_file
        )
        assert not result.success, result.stderr
        assert "No accessible eyaml command" in result.stderr

    def test_diff_yaml_parsing_error(self, script_runner, imparsible_yaml_file, badsyntax_yaml_file):
        result = script_runner.run(
            self.command,
            imparsible_yaml_file,
            badsyntax_yaml_file
        )
        assert not result.success, result.stderr
        assert "YAML parsing error" in result.stderr

    def test_multidoc_missing_lhs_index_error(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
key: value
...
---
second_key: second value
...
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)

        result = script_runner.run(
            self.command,
            lhs_file,
            rhs_file
        )
        assert not result.success, result.stderr
        assert "--left-document-index|-L must be set" in result.stderr

    def test_multidoc_missing_rhs_index_error(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
key: value
...
---
second_key: second value
...
""")

        result = script_runner.run(
            self.command,
            lhs_file,
            rhs_file
        )
        assert not result.success, result.stderr
        assert "--right-document-index|-R must be set" in result.stderr

    def test_multidoc_index_too_high(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--left-document-index=1"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert "DOCUMENT_INDEX is too high" in result.stderr

    def test_no_diff_two_hash_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert result.success, result.stderr
        assert "" == result.stdout

    def test_no_diff_two_aoh_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert result.success, result.stderr
        assert "" == result.stdout

    def test_no_hash_diff_lhs_from_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = subprocess.run(
            [self.command
            , "-"
            , rhs_file
            ]
            , stdout=subprocess.PIPE
            , input=self.lhs_hash_content
            , universal_newlines=True
        )
        assert 0 == result.returncode, result.stderr
        assert "" == result.stdout

    def test_no_aoh_diff_lhs_from_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = subprocess.run(
            [self.command
            , "-"
            , rhs_file
            ]
            , stdout=subprocess.PIPE
            , input=self.lhs_aoh_content
            , universal_newlines=True
        )
        assert 0 == result.returncode, result.stderr
        assert "" == result.stdout

    def test_no_hash_diff_rhs_from_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_hash_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = subprocess.run(
            [self.command
            , lhs_file
            , "-"
            ]
            , stdout=subprocess.PIPE
            , input=self.rhs_hash_content
            , universal_newlines=True
        )
        assert 0 == result.returncode, result.stderr
        assert "" == result.stdout

    def test_no_aoh_diff_rhs_from_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = subprocess.run(
            [self.command
            , lhs_file
            , "-"
            ]
            , stdout=subprocess.PIPE
            , input=self.rhs_aoh_content
            , universal_newlines=True
        )
        assert 0 == result.returncode, result.stderr
        assert "" == result.stdout

    def test_quiet_diff_two_hash_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_hash_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--quiet"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert "" == result.stdout

    def test_simple_diff_two_hash_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_hash_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert self.diff_hash_defaults == result.stdout

    def test_default_diff_two_aoh_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)
        stdout_content = """c [1]
< {"step": 1, "action": "input", "args": ["world"]}
---
> {"step": 3, "action": "quit", "status": 0}

c [2]
< {"step": 2, "action": "print", "message": "Hello, %args[0]!"}
---
> {"step": 2, "action": "print", "message": "A tout %args[0]!"}

c [3]
< {"step": 3, "action": "quit", "status": 0}
---
> {"step": 1, "action": "input", "args": ["le monde"]}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_position_diff_two_aoh_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)
        stdout_content = """c [1]
< {"step": 1, "action": "input", "args": ["world"]}
---
> {"step": 3, "action": "quit", "status": 0}

c [2]
< {"step": 2, "action": "print", "message": "Hello, %args[0]!"}
---
> {"step": 2, "action": "print", "message": "A tout %args[0]!"}

c [3]
< {"step": 3, "action": "quit", "status": 0}
---
> {"step": 1, "action": "input", "args": ["le monde"]}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--aoh=position"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_key_diff_two_aoh_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)
        stdout_content = """c [1]
< {"step": 1, "action": "input", "args": ["world"]}
---
> {"step": 1, "action": "input", "args": ["le monde"]}

c [2]
< {"step": 2, "action": "print", "message": "Hello, %args[0]!"}
---
> {"step": 2, "action": "print", "message": "A tout %args[0]!"}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--aoh=key"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_dpos_diff_two_aoh_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)
        stdout_content = """c [1].step
< 1
---
> 3

a [1].status
> 0

c [1].action
< "input"
---
> "quit"

d [1].args
< ["world"]

c [2].message
< "Hello, %args[0]!"
---
> "A tout %args[0]!"

c [3].step
< 3
---
> 1

c [3].action
< "quit"
---
> "input"

d [3].status
< 0

a [3].args
> ["le monde"]
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--aoh=dpos"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_deep_diff_two_aoh_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--aoh=deep"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert self.diff_aoh_deep == result.stdout

    def test_value_diff_two_aoh_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)
        stdout_content = """d [1]
< {"step": 1, "action": "input", "args": ["world"]}

c [2]
< {"step": 2, "action": "print", "message": "Hello, %args[0]!"}
---
> {"step": 2, "action": "print", "message": "A tout %args[0]!"}

a [3]
> {"step": 1, "action": "input", "args": ["le monde"]}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--aoh=value"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_simple_hash_diff_lhs_from_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_hash_content)

        result = subprocess.run(
            [self.command
            , "-"
            , rhs_file
            ]
            , stdout=subprocess.PIPE
            , input=self.lhs_hash_content
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert self.diff_hash_defaults == result.stdout

    def test_simple_aoh_diff_lhs_from_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)

        result = subprocess.run(
            [self.command
            , "--aoh=deep"
            , "-"
            , rhs_file
            ]
            , stdout=subprocess.PIPE
            , input=self.lhs_aoh_content
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert self.diff_aoh_deep == result.stdout

    def test_simple_hash_diff_rhs_from_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)

        result = subprocess.run(
            [self.command
            , lhs_file
            , "-"
            ]
            , stdout=subprocess.PIPE
            , input=self.rhs_hash_content
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert self.diff_hash_defaults == result.stdout

    def test_simple_aoh_diff_rhs_from_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)

        result = subprocess.run(
            [self.command
            , "--aoh=deep"
            , lhs_file
            , "-"
            ]
            , stdout=subprocess.PIPE
            , input=self.rhs_aoh_content
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert self.diff_aoh_deep == result.stdout

    def test_simple_diff_hash_from_nothing_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_hash_content)
        stdout_content = """a key
> "changed value"

a rhs_exclusive
> "value"

a hash
> {"with": {"multiple": "children", "key_value": "pairs"}, "and": {"complex": {"more": "complex"}, "with": {"several_nested": "levels"}}, "including": {"additional": "structure"}}
"""

        result = subprocess.run(
            [self.command
            , "-"
            , rhs_file
            ]
            , stdout=subprocess.PIPE
            , input=""
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout

    def test_simple_diff_aoh_from_nothing_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)
        stdout_content = """a [0]
> {"step": 0, "action": "INITIALIZE"}

a [1]
> {"step": 3, "action": "quit", "status": 0}

a [2]
> {"step": 2, "action": "print", "message": "A tout %args[0]!"}

a [3]
> {"step": 1, "action": "input", "args": ["le monde"]}

a [4]
> {"step": 9, "action": "CLEANUP"}
"""

        result = subprocess.run(
            [self.command
            , "-"
            , rhs_file
            ]
            , stdout=subprocess.PIPE
            , input=""
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout

    def test_simple_diff_hash_from_text_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_hash_content)
        stdout_content = """d -
< "This is a general text file."

a key
> "changed value"

a rhs_exclusive
> "value"

a hash
> {"with": {"multiple": "children", "key_value": "pairs"}, "and": {"complex": {"more": "complex"}, "with": {"several_nested": "levels"}}, "including": {"additional": "structure"}}
"""

        result = subprocess.run(
            [self.command
            , "-"
            , rhs_file
            ]
            , stdout=subprocess.PIPE
            , input="This is a general text file."
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout

    def test_simple_diff_aoh_from_text_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)
        stdout_content = """d -
< "This is a general text file."

a [0]
> {"step": 0, "action": "INITIALIZE"}

a [1]
> {"step": 3, "action": "quit", "status": 0}

a [2]
> {"step": 2, "action": "print", "message": "A tout %args[0]!"}

a [3]
> {"step": 1, "action": "input", "args": ["le monde"]}

a [4]
> {"step": 9, "action": "CLEANUP"}
"""

        result = subprocess.run(
            [self.command
            , "-"
            , rhs_file
            ]
            , stdout=subprocess.PIPE
            , input="This is a general text file."
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout

    def test_simple_diff_hash_into_nothing_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        stdout_content = """d key
< "value"

d lhs_exclusive
< "value"

d hash
< {"with": {"multiple": "child", "key_value": "pairs"}, "and": {"complex": "structure", "with": {"several": "levels"}}}
"""

        result = subprocess.run(
            [self.command
            , lhs_file
            , "-"
            ]
            , stdout=subprocess.PIPE
            , input=""
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout

    def test_simple_diff_aoh_into_nothing_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        stdout_content = """d [0]
< {"step": 0, "action": "INITIALIZE"}

d [1]
< {"step": 1, "action": "input", "args": ["world"]}

d [2]
< {"step": 2, "action": "print", "message": "Hello, %args[0]!"}

d [3]
< {"step": 3, "action": "quit", "status": 0}

d [4]
< {"step": 9, "action": "CLEANUP"}
"""

        result = subprocess.run(
            [self.command
            , lhs_file
            , "-"
            ]
            , stdout=subprocess.PIPE
            , input=""
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout

    def test_simple_diff_hash_into_text_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        stdout_content = """a -
> "This is a general text file."

d key
< "value"

d lhs_exclusive
< "value"

d hash
< {"with": {"multiple": "child", "key_value": "pairs"}, "and": {"complex": "structure", "with": {"several": "levels"}}}
"""

        result = subprocess.run(
            [self.command
            , lhs_file
            , "-"
            ]
            , stdout=subprocess.PIPE
            , input="This is a general text file."
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout

    def test_simple_diff_aoh_into_text_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        stdout_content = """a -
> "This is a general text file."

d [0]
< {"step": 0, "action": "INITIALIZE"}

d [1]
< {"step": 1, "action": "input", "args": ["world"]}

d [2]
< {"step": 2, "action": "print", "message": "Hello, %args[0]!"}

d [3]
< {"step": 3, "action": "quit", "status": 0}

d [4]
< {"step": 9, "action": "CLEANUP"}
"""

        result = subprocess.run(
            [self.command
            , lhs_file
            , "-"
            ]
            , stdout=subprocess.PIPE
            , input="This is a general text file."
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout

    def test_onlysame_diff_two_hash_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_hash_content)
        stdout_content = """s hash.with.key_value
= "pairs"
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--onlysame"
            , "--aoh=deep"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_onlysame_deep_diff_two_aoh_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_aoh_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_aoh_content)
        stdout_content = """s [0].step
= 0

s [0].action
= "INITIALIZE"

s [3].step
= 1

s [3].action
= "input"

s [2].step
= 2

s [2].action
= "print"

s [1].step
= 3

s [1].action
= "quit"

s [1].status
= 0

s [4].step
= 9

s [4].action
= "CLEANUP"
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--onlysame"
            , "--aoh=deep"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_two_aliased_hash_files(self, script_runner, tmp_path_factory):
        """
        Test Anchors, their Aliases, and YAML Merge Operators.

        Also demonstrate that the yaml-diff tool is a FUNCTIONAL comparison of
        two data files, NOT a textual comparison.  In other words, yaml-diff is
        only interested in how the data is represented to YAML/JSON parsers,
        NOT how the YAML/JSON file is constructed.  Immaterial elements like
        comments, white-space, and demarcation symbols are deliberately ignored
        because none of these have any impact on what data YAML/JSON parsers
        actually percieve to be within the files at run-time.

        Users who need a TEXTUAL (non-functional) comparison of two YAML/JSON
        files should use the GNU `diff` command-line tool rather than this
        yaml-diff command-line tool.
        """
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
aliases:
  - &string_value This is a reusable string value.
  - &int_value 5280
some_values: &some_values
  aliased_int: *int_value
  original_float: 3.14159265358
more_values: &more_values
  aliased_string: *string_value
  original_string: This is another reusable string except its in a reusable parent Hash.
collector_hash:
  <<: [ *some_values, *more_values ]
  concrete_string: This is a non-reusable concrete string.
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
# Reusable aliases
aliases:
  - &string_value This is a CHANGED reusable string value.
  - &aliased_int_value 5280

# Reusable numbers reusing one number
some_values: &some_values
  aliased_int: *aliased_int_value
  original_float: 3.14

# Reusable strings reusing one string
more_values: &more_values
  aliased_string: *string_value
  original_string: "This is another reusable string except its in a reusable parent Hash."

# Bring it all together
collector_hash:
  <<: [ *some_values, *more_values ]
  concrete_string: 'This is a non-reusable concrete string.'
""")
        stdout_content = """c aliases[0]
< "This is a reusable string value."
---
> "This is a CHANGED reusable string value."

c some_values.original_float
< 3.14159265358
---
> 3.14

c more_values.aliased_string
< "This is a reusable string value."
---
> "This is a CHANGED reusable string value."

c collector_hash.original_float
< 3.14159265358
---
> 3.14

c collector_hash.aliased_string
< "This is a reusable string value."
---
> "This is a CHANGED reusable string value."
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_simple_diff_two_hash_files_fslash(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_hash_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_hash_content)
        stdout_content = """d /hash/and/complex
< "structure"

c /key
< "value"
---
> "changed value"

a /rhs_exclusive
> "value"

d /lhs_exclusive
< "value"

c /hash/with/multiple
< "child"
---
> "children"

a /hash/and/complex/more
> "complex"

d /hash/and/with/several
< "levels"

a /hash/and/with/several_nested
> "levels"

a /hash/including
> {"additional": "structure"}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--pathsep=/"
            , "--aoh=deep"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    @requireseyaml
    def test_diff_eyaml_allowed(self, script_runner, tmp_path_factory, old_eyaml_keys):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
same_secret_same_crypt: >-
  <KEY>/NSVF5NEeTz
  MvIW862oA8UFtodj]
same_secret_different_crypt: >-
  ENC[<KEY>
  <KEY>
  <KEY>
  <KEY>
  rg/XOLJXzkkyKEoKIFScBT115aedGY60baMtvD1Md9rxi97xCmj6BroatMlM
  Cm266oFnijrQN9Xsb5ZTnGiPMA9hC2y6X+oJeMaG0S6G64EnTwnjAQytWE6a
  J<KEY>yO70RwACV9QknSqoLuUbYpcbU4FHU/xICiWAG
  <KEY>
  R<KEY>
  W<KEY>
  nNuWarGVGx1Bv+6h]
different_secrets: >-
  ENC[PKCS7,<KEY>MAACAQEw
  DQYJKoZIhvcNAQEBBQAEggEAJRw+urxm+Pyt0Xys5UpJUIaZhA0Tt1JuVsLG
  9jiHb9aua+2bBr/kAN8D/+dowOJlVkG6LZ4Uzn+NZboO8Q2JpQeV9CJTqayJ
  eZnRx02298qSrWOogSQUoS/<KEY>
  gAgL5bAXzD2+1MHIRMrf8ascVmTOV4/JMckWznCseM+uJ7PkR12044mWhuvk
  aJUjaXFXIEYhA4+jjKWdlOTWJ<KEY>aNZVlcf8X1WuoX4f1iPP53z
  mATu0eDx8D5XwQnygUMrPWrlCyoIqRIcwU6f5iv+HT1EWEvSI5+i7bByx0hk
  apUR+TBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBCgVC5h5pznSfACl7+Q
  ff+mgDBAZPMofXWfguD6OgcXu0/QMz90QHAN4bu+CHHZLZ+8X3qSgKHszijK
  eEeStAMoq50=]
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
same_secret_same_crypt: >-
  ENC[PKCS7,MIIBygYJKoZIhvcNAQcDoIIBuzCCAbcCAQAxggEhMIIBHQIBADAFMAACAQEw
  DQYJKoZIhvcNAQEBBQAEggEAP5tXc8gPp1p5945Ih/i/k/OqvoDrWi/F05/V
  EhlgUwXgNer0Y5C7G/FE4Gt5nasoolbPQTMVuq+CW8qQ6wsnVrB60SCDvy5q
  <KEY>]
same_secret_different_crypt: >-
  ENC[PKCS7,MIIBygYJKoZIhvcNAQcDoIIBuzCCAbcCAQAxggEhMIIBHQIBADAFMAACAQEw
  DQYJKoZIhvcNAQEBBQAEggEAV/S/jxC79aiKR1UnPxcrPo7bLpSpsoUqJfdQ
  znMp0LJrqacIcrq+jFRLqFUv2dDcTRnReP5CZy4HEJw73710Ngb+sJLQeCE9
  f8qYvjKAlWyrw0Strpwe5BQT4g7ph5GX3lOqjCBJbqRPE9XfhI9DPljkUzBB
  IQ8zVZz/zy5TbBCRZm7RKPjbczTMaHRRQb0fEKnK7tTdHIucNRQh0AZ9ZGuJ
  8TchxlBhgtwjKU0NxbpQyi/hVyv7Dw8/wSq3Wp5nFYJj1uFxYES0sw6QAsM+
  1LzY2hg+RCzL3gxU724gH0xRCv346tKoyqzVxtO+knLVh/m8HulrXJABKn0/
  ZJrBezCBjAYJKoZIhvcNAQcBMB0GCWCGSAFlAwQBKgQQMvmLomzj48fPsA1H
  DVQiaoBgctgTfmmKEaEoCYJqd4WXpJeb96viMyTXRaa8Pt0rl22mbt92qMUk
  witfhD7lzteg1k2tunXQx8w37vx60kqY3aEXV8crQb1TQdBUuZIks1RnLFur
  14/eAgRAn37NhJli]
different_secrets: >-
  ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEw
  DQYJKoZIhvcNAQEBBQAEggEAm9Sw3jUCLMOKU0wpQgu7kW4yO/MvoLbQpWMB
  KKFEssxhJ0Kqc5Q+2cTAk6vo5K7GopVYr5iCaaoxLmCJq3ke1XBR6O182q/2
  vcvgqTVq3OaaMR3qji1edJQd6NJuqpuV+tIf6RCktt5+9wlIXLxujnaYxmr1
  vrEMXnb0R6PWunXsTAlDDrCVMC6iXIvbhsP2GF8zhhuTkCXp1LTDuvj3aSso
  iloELuCdCGO7iFTXPuPy4nrgXjlaVnGftoDmVukDP8PUzyEBT1a9ZXUjrswS
  sXzCsTnEGIpPlIe84Nvk43osbVw2sOgwod7Uko7KmdXVFAh8l15BoW5E9uRw
  y2XahTBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBAIA2FJ1Fo38jwnbHs8
  V8GOgDAaCmR9jyjK/0f0V2WnRF+nPS21sNoB0qONn1V0GwAQbu0yk7QS5y8q
  4OTZEGxziGU=]
""")
        stdout_content = """c different_secrets
< "ENC[PKCS7,<KEY>=]"
---
> "ENC[<KEY>
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--privatekey={}".format(old_eyaml_keys[0])
            , "--publickey={}".format(old_eyaml_keys[1])
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_eyaml_disallowed(self, script_runner, tmp_path_factory, old_eyaml_keys):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
same_secret_same_crypt: >
  ENC[PKCS7,<KEY>
  MvIW862oA8UFtodj]
same_secret_different_crypt: >
  ENC[PKCS7,<KEY>]
different_secrets: >
  <KEY>
  ff+<KEY>
  eEeStAMoq50=]
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
same_secret_same_crypt: >
  ENC[PKCS7,MIIBygYJKoZIhvcNAQcDoIIBuzCCAbcCAQAxggEhMIIBHQIBADAFMAACAQEw
  DQYJKoZIhvcNAQEBBQAEggEAP5tXc8gPp1p5945Ih/i/k/OqvoDrWi/F05/V
  EhlgUwXgNer0Y5C7G/FE4Gt5nasoolbPQTMVuq+CW8qQ6wsnVrB60SCDvy5q
  9k7WGHyQU5n6UR00/RLhctStGe6nN/zIsoYLQyyY/+xJaHAwahB/GkzFPk9S
  <KEY>]
same_secret_different_crypt: >
  <KEY>
  <KEY>]
different_secrets: >
  <KEY>UDBAEqBBAIA2FJ1Fo38jwnbHs8
  V8GOgDAaCmR9jyjK/0f0V2WnRF+nPS21sNoB0qONn1V0GwAQbu0yk7QS5y8q
  4OTZEGxziGU=]
""")
        stdout_content = """c same_secret_different_crypt
< "ENC[PKCS7,MIIBygYJKoZIhvcNAQcDoIIBuzCCAbcCAQAxggEhMIIBHQIBADAFMAACAQEw DQYJKoZIhvcNAQEBBQAEggEAYUDg4y4+LXY0IdEDYFgxfxRJ3dfkOPwTSLxl A91x5IQlgQYQpXkgkFEeJj3EXdYwt9K6prtFywokVQoOaWgXWWV+Tf0lF5P0 0sw4LH7MgaszKPpiOHxx9hTmexEIusF+tzvQBOD1zHfDdkZQ0v9R3JLHckub rg/XOLJXzkkyKEoKIFScBT115aedGY60baMtvD1Md9rxi97xCmj6BroatMlM Cm266oFnijrQN9Xsb5ZTnGiPMA9hC2y6X+oJeMaG0S6G64EnTwnjAQytWE6a JM1/YXVKIoE2c/E44/m74kuyO70RwACV9QknSqoLuUbYpcbU4FHU/xICiWAG CaTz9zCBjAYJKoZIhvcNAQcBMB0GCWCGSAFlAwQBKgQQ9kFVNmG9heK0WyWU R1kfyIBgCIJzi+XnQMS9w85Mbq6BaNPpJrU7ZaoHQ6c3Ps9sgJStVDQNmrbL WAP8fEC6S7V07rA7hp4YomvAJRJjDIK7M2AzXDNzupuAh4crF905AR4TF+Jd nNuWarGVGx1Bv+6h]"
---
> "<KEY>

c different_secrets
< "<KEY>]"
---
> "ENC[<KEY>
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--ignore-eyaml-values"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_two_multiline_string_hash_files(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
folded_string: >
  This is
  one really long
  string.  It
  is presented in
  YAML "folded"
  format.  This will
  cause all of the
  new-line characters
  to be replaced with
  single spaces
  when this value
  is read by a
  YAML parser.

literal_string: |
  This is another
  really long string.
  It is presented in
  YAML "literal"
  format.  When a
  YAML parser reads
  this value, all of
  these new-line
  characters will be
  preserved.
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
folded_string: >
  This CHANGED
  one really long
  string.  It
  is presented in
  YAML "folded"
  format.  This will
  cause all of the
  new-line characters
  to be replaced with
  single spaces
  when this value
  is read by a
  YAML parser.

literal_string: |
  This is another
  really long CHANGED string.
  It is presented in
  YAML "literal"
  format.  When a
  YAML parser reads
  this value, all of
  these new-line
  characters will be
  preserved.
""")
        stdout_content = r"""c folded_string
< "This is one really long string.  It is presented in YAML \"folded\" format.  This will cause all of the new-line characters to be replaced with single spaces when this value is read by a YAML parser."
---
> "This CHANGED one really long string.  It is presented in YAML \"folded\" format.  This will cause all of the new-line characters to be replaced with single spaces when this value is read by a YAML parser."

c literal_string
< "This is another
< really long string.
< It is presented in
< YAML \"literal\"
< format.  When a
< YAML parser reads
< this value, all of
< these new-line
< characters will be
< preserved."
---
> "This is another
> really long CHANGED string.
> It is presented in
> YAML \"literal\"
> format.  When a
> YAML parser reads
> this value, all of
> these new-line
> characters will be
> preserved."
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_two_multiline_string_hash_files_verbosely(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
folded_string: >
  This is
  one really long
  string.  It
  is presented in
  YAML "folded"
  format.  This will
  cause all of the
  new-line characters
  to be replaced with
  single spaces
  when this value
  is read by a
  YAML parser.

literal_string: |
  This is another
  really long string.
  It is presented in
  YAML "literal"
  format.  When a
  YAML parser reads
  this value, all of
  these new-line
  characters will be
  preserved.
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
folded_string: >
  This CHANGED
  one really long
  string.  It
  is presented in
  YAML "folded"
  format.  This will
  cause all of the
  new-line characters
  to be replaced with
  single spaces
  when this value
  is read by a
  YAML parser.

literal_string: |
  This is another
  really long CHANGED string.
  It is presented in
  YAML "literal"
  format.  When a
  YAML parser reads
  this value, all of
  these new-line
  characters will be
  preserved.
""")
        stdout_content = r"""c1.0.0.1.0.0 folded_string
< "This is one really long string.  It is presented in YAML \"folded\" format.  This will cause all of the new-line characters to be replaced with single spaces when this value is read by a YAML parser."
---
> "This CHANGED one really long string.  It is presented in YAML \"folded\" format.  This will cause all of the new-line characters to be replaced with single spaces when this value is read by a YAML parser."

c1.0.1.1.0.1 literal_string
< "This is another
< really long string.
< It is presented in
< YAML \"literal\"
< format.  When a
< YAML parser reads
< this value, all of
< these new-line
< characters will be
< preserved."
---
> "This is another
> really long CHANGED string.
> It is presented in
> YAML \"literal\"
> format.  When a
> YAML parser reads
> this value, all of
> these new-line
> characters will be
> preserved."
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--verbose"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_array_by_default(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_array_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_array_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert self.diff_array_defaults == result.stdout

    def test_diff_array_by_position(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_array_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_array_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--arrays=position"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert self.diff_array_defaults == result.stdout

    def test_diff_array_by_value(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_array_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_array_content)
        stdout_content = """a [0]
> "zeta"

a [5]
> "gamma"

c [6]
< "delta"
---
> "phi"

d [4]
< "delta"

d [8]
< "alpha"

d [9]
< "theta"
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--arrays=value"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_add_array_element(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
- 0
- 1
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
- 0
- 1
- 2
""")
        stdout_content = """a [2]
> 2
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_add_aoh_element_default(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 0
  name: zero
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 0
  name: zero
- id: 1
  name: uno
""")
        stdout_content = """a [1]
> {"id": 1, "name": "uno"}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_add_aoh_element_key(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 1
  name: uno
- id: 0
  name: zero
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 0
  name: zero
- id: 2
  name: dos
- id: 1
  name: uno
""")
        stdout_content = """a [1]
> {"id": 2, "name": "dos"}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--aoh=key"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_delete_aoh_element_default(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 0
  name: zero
- id: 1
  name: uno
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 0
  name: zero
""")
        stdout_content = """d [1]
< {"id": 1, "name": "uno"}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_delete_aoh_element_key(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 0
  name: zero
- id: 1
  name: uno
- id: 2
  name: dos
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 1
  name: uno
- id: 0
  name: zero
""")
        stdout_content = """d [2]
< {"id": 2, "name": "dos"}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--aoh=key"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_unkeyed_aoh_elements(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 1
  name: uno
- id: 0
  name: zero
- name: tres
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
- id: 0
  name: zero
- name: dos
- id: 1
  name: uno
""")
        stdout_content = """a [1]
> {"name": "dos"}

d [2]
< {"name": "tres"}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--aoh=key"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_diff_custom_aoh_keyed_elements(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
products:
  - product: doodad
    sku: 0-000-0001-0
    availability:
      start:
        date: 2020-10-10
        time: 08:00
      stop:
        date: 2020-10-29
        time: 17:00
    dimensions:
      width: 5
      height: 5
      depth: 5
      weight: 10
  - product: dumdow
    sku: 0-000-0002-0
    availability:
      start:
        date: 2020-10-23
        time: 08:00
      stop:
        date: 2020-11-23
        time: 17:00
    dimensions:
      width: 3
      height: 3
      depth: 3
      weight: 27
  - product: doohickey
    sku: 0-000-0003-0
    availability:
      start:
        date: 2020-08-01
        time: 10:00
      stop:
        date: 2020-09-25
        time: 10:00
    dimensions:
      width: 1
      height: 2
      depth: 3
      weight: 4
  - product: widget
    sku: 0-000-0004-0
    availability:
      start:
        date: 2020-01-01
        time: 12:00
      stop:
        date: 2020-01-01
        time: 16:00
    dimensions:
      width: 9
      height: 10
      depth: 1
      weight: 4
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
products:
  - sku: 0-000-0001-0
    availability:
      start:
        date: 2020-10-10
        time: 08:00
      stop:
        date: 2020-10-29
        time: 17:00
    dimensions:
      width: 5
      height: 5
      depth: 5
      weight: 10
  - sku: 0-000-0002-0
    availability:
      start:
        date: 2020-10-23
        time: 08:00
      stop:
        date: 2020-11-23
        time: 17:00
    dimensions:
      width: 4
      height: 3
      depth: 3
      weight: 27
  - dimensions:
      width: 9
      height: 10
      depth: 1
      weight: 4
    sku: 0-000-0004-0
    availability:
      start:
        date: 2020-01-01
        time: 12:00
      stop:
        date: 2020-01-01
        time: 16:00
  - product: doohickey
    availability:
      stop:
        date: 2020-09-25
        time: 10:00
      start:
        date: 2020-08-01
        time: 10:00
    dimensions:
      weight: 4
      width: 1
      depth: 3
      height: 2
""")
        config_file = create_temp_yaml_file(tmp_path_factory, """[rules]
/products = key

[keys]
/products[product=doohickey] = product
""")
        stdout_content = """c products[0]
< {"product": "doodad", "sku": "0-000-0001-0", "availability": {"start": {"date": "2020-10-10", "time": "08:00"}, "stop": {"date": "2020-10-29", "time": "17:00"}}, "dimensions": {"width": 5, "height": 5, "depth": 5, "weight": 10}}
---
> {"sku": "0-000-0001-0", "availability": {"start": {"date": "2020-10-10", "time": "08:00"}, "stop": {"date": "2020-10-29", "time": "17:00"}}, "dimensions": {"width": 5, "height": 5, "depth": 5, "weight": 10}}

c products[1]
< {"product": "dumdow", "sku": "0-000-0002-0", "availability": {"start": {"date": "2020-10-23", "time": "08:00"}, "stop": {"date": "2020-11-23", "time": "17:00"}}, "dimensions": {"width": 3, "height": 3, "depth": 3, "weight": 27}}
---
> {"sku": "0-000-0002-0", "availability": {"start": {"date": "2020-10-23", "time": "08:00"}, "stop": {"date": "2020-11-23", "time": "17:00"}}, "dimensions": {"width": 4, "height": 3, "depth": 3, "weight": 27}}

c products[2]
< {"product": "doohickey", "sku": "0-000-0003-0", "availability": {"start": {"date": "2020-08-01", "time": "10:00"}, "stop": {"date": "2020-09-25", "time": "10:00"}}, "dimensions": {"width": 1, "height": 2, "depth": 3, "weight": 4}}
---
> {"product": "doohickey", "availability": {"stop": {"date": "2020-09-25", "time": "10:00"}, "start": {"date": "2020-08-01", "time": "10:00"}}, "dimensions": {"weight": 4, "width": 1, "depth": 3, "height": 2}}

c products[3]
< {"product": "widget", "sku": "0-000-0004-0", "availability": {"start": {"date": "2020-01-01", "time": "12:00"}, "stop": {"date": "2020-01-01", "time": "16:00"}}, "dimensions": {"width": 9, "height": 10, "depth": 1, "weight": 4}}
---
> {"dimensions": {"width": 9, "height": 10, "depth": 1, "weight": 4}, "sku": "0-000-0004-0", "availability": {"start": {"date": "2020-01-01", "time": "12:00"}, "stop": {"date": "2020-01-01", "time": "16:00"}}}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , "--config={}".format(config_file)
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout

    def test_comprehensive_tag_diffs(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, """---
aliases:
  - &one One
  - &two !tag_two Two
  - &three !tag_three Three

hash_one:
  key_one: *one
  key_two: *two
  key_three: *three
  *one : *two
  *two : *one
  *three : *three

hash_two:
  key_one: *one
  key_two: *two
  *one : *two
  *two : *one
  *three : *three
""")
        rhs_file = create_temp_yaml_file(tmp_path_factory, """---
aliases:
  - &one !tag_one One
  - &two Two
  - &three !tag_tres Three

hash_one:
  key_one: *one
  key_two: *two
  key_three: *three
  *one : *two
  *two : *one
  *three : *three

hash_two: !example
  key_one: *one
  key_two: *two
  *one : *two
  *two : *one
  *three : *three
""")
        stdout_content = """c aliases[0]
< "One"
---
> !tag_one "One"

c aliases[1]
< !tag_two "Two"
---
> "Two"

c aliases[2]
< !tag_three "Three"
---
> !tag_tres "Three"

c hash_one.key_one
< "One"
---
> !tag_one "One"

a hash_one.One !tag_one
> "Two"

a hash_one.Two
> !tag_one "One"

a hash_one.Three !tag_tres
> !tag_tres "Three"

c hash_one.key_two
< !tag_two "Two"
---
> "Two"

c hash_one.key_three
< !tag_three "Three"
---
> !tag_tres "Three"

d hash_one.One
< !tag_two "Two"

d hash_one.Two !tag_two
< "One"

d hash_one.Three !tag_three
< !tag_three "Three"

a hash_two !example
> {"key_one": "One", "key_two": "Two", "One": "Two", "Two": "One", "Three": "Three"}

d hash_two
< {"key_one": "One", "key_two": "Two", "One": "Two", "Two": "One", "Three": "Three"}
"""

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(merged_yaml_content)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert stdout_content == result.stdout


    def test_diff_set_normal(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_set_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_set_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(self.diff_set_defaults)

        result = script_runner.run(
            self.command
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert self.diff_set_defaults == result.stdout

    def test_diff_set_verbose(self, script_runner, tmp_path_factory):
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_set_content)
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_set_content)

        # DEBUG
        # print("LHS File:  {}".format(lhs_file))
        # print("RHS File:  {}".format(rhs_file))
        # print("Expected Output:")
        # print(self.diff_set_defaults)

        result = script_runner.run(
            self.command
            , "--verbose"
            , lhs_file
            , rhs_file)
        assert not result.success, result.stderr
        assert self.diff_set_verbose == result.stdout

    def test_simple_diff_set_from_nothing_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        rhs_file = create_temp_yaml_file(tmp_path_factory, self.rhs_set_content)
        stdout_content = """a four
> "four"

a three
> "three"

a two
> "two"
"""

        result = subprocess.run(
            [self.command
            , "-"
            , rhs_file
            ]
            , stdout=subprocess.PIPE
            , input=""
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout

    def test_simple_diff_set_into_nothing_via_stdin(self, script_runner, tmp_path_factory):
        import subprocess
        lhs_file = create_temp_yaml_file(tmp_path_factory, self.lhs_set_content)
        stdout_content = """d one
< "one"

d two
< "two"

d four
< "four"
"""

        result = subprocess.run(
            [self.command
            , lhs_file
            , "-"
            ]
            , stdout=subprocess.PIPE
            , input=""
            , universal_newlines=True
        )
        assert 1 == result.returncode, result.stderr
        assert stdout_content == result.stdout
Tests for the yaml-diff command-line tool. ### # Simple Hash comparisons ### --- key: value hash:   with:     multiple: child     key_value: pairs   and:     complex: structure     with:       several: levels lhs_exclusive: value --- key: changed value hash:   with:     multiple: children     key_value: pairs   and:     complex:       more: complex     with:       several_nested: levels   including:     additional: structure rhs_exclusive: value ### # Simple Array comparisons ### --- - alpha - mu - psi - beta - delta - chi - delta - gamma - alpha - theta --- - zeta - mu - psi - alpha - gamma - gamma - phi - beta - chi c [0] < "alpha" --- > "zeta"  c [3] < "beta" --- > "alpha"  c [4] < "delta" --- > "gamma"  c [5] < "chi" --- > "gamma"  c [6] < "delta" --- > "phi"  c [7] < "gamma" --- > "beta"  c [8] < "alpha" --- > "chi"  d [9] < "theta" ### # Simple Array-of-Hashes comparisons ### --- - step: 0   action: INITIALIZE - step: 1   action: input   args:     - world - step: 2   action: print   message: Hello, %args[0]! - step: 3   action: quit   status: 0 - step: 9   action: CLEANUP --- - step: 0   action: INITIALIZE - step: 3   action: quit   status: 0 - step: 2   action: print   message: A tout %args[0]! - step: 1   action: input   args:     - le monde - step: 9   action: CLEANUP d hash.and.complex < "structure"  c key < "value" --- > "changed value"  a rhs_exclusive > "value"  d lhs_exclusive < "value"  c hash.with.multiple < "child" --- > "children"  a hash.and.complex.more > "complex"  d hash.and.with.several < "levels"  a hash.and.with.several_nested > "levels"  a hash.including > {"additional": "structure"} c [3].args[0] < "world" --- > "le monde"  c [2].message < "Hello, %args[0]!" --- > "A tout %args[0]!" ### # Simple Set comparisons ### --- !!set ? one ? two ? four --- !!set ? four ? three ? two d one < "one"  a three > "three" d0.4.0.0.4.0 one < "one"  a0.4.0.0.4.1 three > "three" ---         aliases:           - &encryptedScalar >             ENC[PKCS7,MIIx...broken-on-purpose...==] --- key: value ... --- second_key: second value ... --- key: value ... --- second_key: second value ... # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) c [1] < {"step": 1, "action": "input", "args": ["world"]} --- > {"step": 3, "action": "quit", "status": 0}  c [2] < {"step": 2, "action": "print", "message": "Hello, %args[0]!"} --- > {"step": 2, "action": "print", "message": "A tout %args[0]!"}  c [3] < {"step": 3, "action": "quit", "status": 0} --- > {"step": 1, "action": "input", "args": ["le monde"]} # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) c [1] < {"step": 1, "action": "input", "args": ["world"]} --- > {"step": 3, "action": "quit", "status": 0}  c [2] < {"step": 2, "action": "print", "message": "Hello, %args[0]!"} --- > {"step": 2, "action": "print", "message": "A tout %args[0]!"}  c [3] < {"step": 3, "action": "quit", "status": 0} --- > {"step": 1, "action": "input", "args": ["le monde"]} # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) c [1] < {"step": 1, "action": "input", "args": ["world"]} --- > {"step": 1, "action": "input", "args": ["le monde"]}  c [2] < {"step": 2, "action": "print", "message": "Hello, %args[0]!"} --- > {"step": 2, "action": "print", "message": "A tout %args[0]!"} # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) c [1].step < 1 --- > 3  a [1].status > 0  c [1].action < "input" --- > "quit"  d [1].args < ["world"]  c [2].message < "Hello, %args[0]!" --- > "A tout %args[0]!"  c [3].step < 3 --- > 1  c [3].action < "quit" --- > "input"  d [3].status < 0  a [3].args > ["le monde"] # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) d [1] < {"step": 1, "action": "input", "args": ["world"]}  c [2] < {"step": 2, "action": "print", "message": "Hello, %args[0]!"} --- > {"step": 2, "action": "print", "message": "A tout %args[0]!"}  a [3] > {"step": 1, "action": "input", "args": ["le monde"]} # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) a key > "changed value"  a rhs_exclusive > "value"  a hash > {"with": {"multiple": "children", "key_value": "pairs"}, "and": {"complex": {"more": "complex"}, "with": {"several_nested": "levels"}}, "including": {"additional": "structure"}} a [0] > {"step": 0, "action": "INITIALIZE"}  a [1] > {"step": 3, "action": "quit", "status": 0}  a [2] > {"step": 2, "action": "print", "message": "A tout %args[0]!"}  a [3] > {"step": 1, "action": "input", "args": ["le monde"]}  a [4] > {"step": 9, "action": "CLEANUP"} d - < "This is a general text file."  a key > "changed value"  a rhs_exclusive > "value"  a hash > {"with": {"multiple": "children", "key_value": "pairs"}, "and": {"complex": {"more": "complex"}, "with": {"several_nested": "levels"}}, "including": {"additional": "structure"}} d - < "This is a general text file."  a [0] > {"step": 0, "action": "INITIALIZE"}  a [1] > {"step": 3, "action": "quit", "status": 0}  a [2] > {"step": 2, "action": "print", "message": "A tout %args[0]!"}  a [3] > {"step": 1, "action": "input", "args": ["le monde"]}  a [4] > {"step": 9, "action": "CLEANUP"} d key < "value"  d lhs_exclusive < "value"  d hash < {"with": {"multiple": "child", "key_value": "pairs"}, "and": {"complex": "structure", "with": {"several": "levels"}}} d [0] < {"step": 0, "action": "INITIALIZE"}  d [1] < {"step": 1, "action": "input", "args": ["world"]}  d [2] < {"step": 2, "action": "print", "message": "Hello, %args[0]!"}  d [3] < {"step": 3, "action": "quit", "status": 0}  d [4] < {"step": 9, "action": "CLEANUP"} a - > "This is a general text file."  d key < "value"  d lhs_exclusive < "value"  d hash < {"with": {"multiple": "child", "key_value": "pairs"}, "and": {"complex": "structure", "with": {"several": "levels"}}} a - > "This is a general text file."  d [0] < {"step": 0, "action": "INITIALIZE"}  d [1] < {"step": 1, "action": "input", "args": ["world"]}  d [2] < {"step": 2, "action": "print", "message": "Hello, %args[0]!"}  d [3] < {"step": 3, "action": "quit", "status": 0}  d [4] < {"step": 9, "action": "CLEANUP"} s hash.with.key_value = "pairs" # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) s [0].step = 0  s [0].action = "INITIALIZE"  s [3].step = 1  s [3].action = "input"  s [2].step = 2  s [2].action = "print"  s [1].step = 3  s [1].action = "quit"  s [1].status = 0  s [4].step = 9  s [4].action = "CLEANUP" # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) Test Anchors, their Aliases, and YAML Merge Operators.          Also demonstrate that the yaml-diff tool is a FUNCTIONAL comparison of         two data files, NOT a textual comparison.  In other words, yaml-diff is         only interested in how the data is represented to YAML/JSON parsers,         NOT how the YAML/JSON file is constructed.  Immaterial elements like         comments, white-space, and demarcation symbols are deliberately ignored         because none of these have any impact on what data YAML/JSON parsers         actually percieve to be within the files at run-time.          Users who need a TEXTUAL (non-functional) comparison of two YAML/JSON         files should use the GNU `diff` command-line tool rather than this         yaml-diff command-line tool. --- aliases:   - &string_value This is a reusable string value.   - &int_value 5280 some_values: &some_values   aliased_int: *int_value   original_float: 3.14159265358 more_values: &more_values   aliased_string: *string_value   original_string: This is another reusable string except its in a reusable parent Hash. collector_hash:   <<: [ *some_values, *more_values ]   concrete_string: This is a non-reusable concrete string. --- # Reusable aliases aliases:   - &string_value This is a CHANGED reusable string value.   - &aliased_int_value 5280  # Reusable numbers reusing one number some_values: &some_values   aliased_int: *aliased_int_value   original_float: 3.14  # Reusable strings reusing one string more_values: &more_values   aliased_string: *string_value   original_string: "This is another reusable string except its in a reusable parent Hash."  # Bring it all together collector_hash:   <<: [ *some_values, *more_values ]   concrete_string: 'This is a non-reusable concrete string.' c aliases[0] < "This is a reusable string value." --- > "This is a CHANGED reusable string value."  c some_values.original_float < 3.14159265358 --- > 3.14  c more_values.aliased_string < "This is a reusable string value." --- > "This is a CHANGED reusable string value."  c collector_hash.original_float < 3.14159265358 --- > 3.14  c collector_hash.aliased_string < "This is a reusable string value." --- > "This is a CHANGED reusable string value." # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) d /hash/and/complex < "structure"  c /key < "value" --- > "changed value"  a /rhs_exclusive > "value"  d /lhs_exclusive < "value"  c /hash/with/multiple < "child" --- > "children"  a /hash/and/complex/more > "complex"  d /hash/and/with/several < "levels"  a /hash/and/with/several_nested > "levels"  a /hash/including > {"additional": "structure"} # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) --- same_secret_same_crypt: >-   <KEY>/NSVF5NEeTz   MvIW862oA8UFtodj] same_secret_different_crypt: >-   ENC[<KEY>   <KEY>   <KEY>   <KEY>   rg/XOLJXzkkyKEoKIFScBT115aedGY60baMtvD1Md9rxi97xCmj6BroatMlM   Cm266oFnijrQN9Xsb5ZTnGiPMA9hC2y6X+oJeMaG0S6G64EnTwnjAQytWE6a   J<KEY>yO70RwACV9QknSqoLuUbYpcbU4FHU/xICiWAG   <KEY>   R<KEY>   W<KEY>   nNuWarGVGx1Bv+6h] different_secrets: >-   ENC[PKCS7,<KEY>MAACAQEw   DQYJKoZIhvcNAQEBBQAEggEAJRw+urxm+Pyt0Xys5UpJUIaZhA0Tt1JuVsLG   9jiHb9aua+2bBr/kAN8D/+dowOJlVkG6LZ4Uzn+NZboO8Q2JpQeV9CJTqayJ   eZnRx02298qSrWOogSQUoS/<KEY>   gAgL5bAXzD2+1MHIRMrf8ascVmTOV4/JMckWznCseM+uJ7PkR12044mWhuvk   aJUjaXFXIEYhA4+jjKWdlOTWJ<KEY>aNZVlcf8X1WuoX4f1iPP53z   mATu0eDx8D5XwQnygUMrPWrlCyoIqRIcwU6f5iv+HT1EWEvSI5+i7bByx0hk   apUR+TBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBCgVC5h5pznSfACl7+Q   ff+mgDBAZPMofXWfguD6OgcXu0/QMz90QHAN4bu+CHHZLZ+8X3qSgKHszijK   eEeStAMoq50=] --- same_secret_same_crypt: >-   ENC[PKCS7,MIIBygYJKoZIhvcNAQcDoIIBuzCCAbcCAQAxggEhMIIBHQIBADAFMAACAQEw   DQYJKoZIhvcNAQEBBQAEggEAP5tXc8gPp1p5945Ih/i/k/OqvoDrWi/F05/V   EhlgUwXgNer0Y5C7G/FE4Gt5nasoolbPQTMVuq+CW8qQ6wsnVrB60SCDvy5q   <KEY>] same_secret_different_crypt: >-   ENC[PKCS7,MIIBygYJKoZIhvcNAQcDoIIBuzCCAbcCAQAxggEhMIIBHQIBADAFMAACAQEw   DQYJKoZIhvcNAQEBBQAEggEAV/S/jxC79aiKR1UnPxcrPo7bLpSpsoUqJfdQ   znMp0LJrqacIcrq+jFRLqFUv2dDcTRnReP5CZy4HEJw73710Ngb+sJLQeCE9   f8qYvjKAlWyrw0Strpwe5BQT4g7ph5GX3lOqjCBJbqRPE9XfhI9DPljkUzBB   IQ8zVZz/zy5TbBCRZm7RKPjbczTMaHRRQb0fEKnK7tTdHIucNRQh0AZ9ZGuJ   8TchxlBhgtwjKU0NxbpQyi/hVyv7Dw8/wSq3Wp5nFYJj1uFxYES0sw6QAsM+   1LzY2hg+RCzL3gxU724gH0xRCv346tKoyqzVxtO+knLVh/m8HulrXJABKn0/   ZJrBezCBjAYJKoZIhvcNAQcBMB0GCWCGSAFlAwQBKgQQMvmLomzj48fPsA1H   DVQiaoBgctgTfmmKEaEoCYJqd4WXpJeb96viMyTXRaa8Pt0rl22mbt92qMUk   witfhD7lzteg1k2tunXQx8w37vx60kqY3aEXV8crQb1TQdBUuZIks1RnLFur   14/eAgRAn37NhJli] different_secrets: >-   ENC[PKCS7,MIIBmQYJKoZIhvcNAQcDoIIBijCCAYYCAQAxggEhMIIBHQIBADAFMAACAQEw   DQYJKoZIhvcNAQEBBQAEggEAm9Sw3jUCLMOKU0wpQgu7kW4yO/MvoLbQpWMB   KKFEssxhJ0Kqc5Q+2cTAk6vo5K7GopVYr5iCaaoxLmCJq3ke1XBR6O182q/2   vcvgqTVq3OaaMR3qji1edJQd6NJuqpuV+tIf6RCktt5+9wlIXLxujnaYxmr1   vrEMXnb0R6PWunXsTAlDDrCVMC6iXIvbhsP2GF8zhhuTkCXp1LTDuvj3aSso   iloELuCdCGO7iFTXPuPy4nrgXjlaVnGftoDmVukDP8PUzyEBT1a9ZXUjrswS   sXzCsTnEGIpPlIe84Nvk43osbVw2sOgwod7Uko7KmdXVFAh8l15BoW5E9uRw   y2XahTBcBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBAIA2FJ1Fo38jwnbHs8   V8GOgDAaCmR9jyjK/0f0V2WnRF+nPS21sNoB0qONn1V0GwAQbu0yk7QS5y8q   4OTZEGxziGU=] c different_secrets < "ENC[PKCS7,<KEY>=]" --- > "ENC[<KEY> # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) --- same_secret_same_crypt: >   ENC[PKCS7,<KEY>   MvIW862oA8UFtodj] same_secret_different_crypt: >   ENC[PKCS7,<KEY>] different_secrets: >   <KEY>   ff+<KEY>   eEeStAMoq50=] --- same_secret_same_crypt: >   ENC[PKCS7,MIIBygYJKoZIhvcNAQcDoIIBuzCCAbcCAQAxggEhMIIBHQIBADAFMAACAQEw   DQYJKoZIhvcNAQEBBQAEggEAP5tXc8gPp1p5945Ih/i/k/OqvoDrWi/F05/V   EhlgUwXgNer0Y5C7G/FE4Gt5nasoolbPQTMVuq+CW8qQ6wsnVrB60SCDvy5q   9k7WGHyQU5n6UR00/RLhctStGe6nN/zIsoYLQyyY/+xJaHAwahB/GkzFPk9S   <KEY>] same_secret_different_crypt: >   <KEY>   <KEY>] different_secrets: >   <KEY>UDBAEqBBAIA2FJ1Fo38jwnbHs8   V8GOgDAaCmR9jyjK/0f0V2WnRF+nPS21sNoB0qONn1V0GwAQbu0yk7QS5y8q   4OTZEGxziGU=] c same_secret_different_crypt < "ENC[PKCS7,MIIBygYJKoZIhvcNAQcDoIIBuzCCAbcCAQAxggEhMIIBHQIBADAFMAACAQEw DQYJKoZIhvcNAQEBBQAEggEAYUDg4y4+LXY0IdEDYFgxfxRJ3dfkOPwTSLxl A91x5IQlgQYQpXkgkFEeJj3EXdYwt9K6prtFywokVQoOaWgXWWV+Tf0lF5P0 0sw4LH7MgaszKPpiOHxx9hTmexEIusF+tzvQBOD1zHfDdkZQ0v9R3JLHckub rg/XOLJXzkkyKEoKIFScBT115aedGY60baMtvD1Md9rxi97xCmj6BroatMlM Cm266oFnijrQN9Xsb5ZTnGiPMA9hC2y6X+oJeMaG0S6G64EnTwnjAQytWE6a JM1/YXVKIoE2c/E44/m74kuyO70RwACV9QknSqoLuUbYpcbU4FHU/xICiWAG CaTz9zCBjAYJKoZIhvcNAQcBMB0GCWCGSAFlAwQBKgQQ9kFVNmG9heK0WyWU R1kfyIBgCIJzi+XnQMS9w85Mbq6BaNPpJrU7ZaoHQ6c3Ps9sgJStVDQNmrbL WAP8fEC6S7V07rA7hp4YomvAJRJjDIK7M2AzXDNzupuAh4crF905AR4TF+Jd nNuWarGVGx1Bv+6h]" --- > "<KEY>  c different_secrets < "<KEY>]" --- > "ENC[<KEY> # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) --- folded_string: >   This is   one really long   string.  It   is presented in   YAML "folded"   format.  This will   cause all of the   new-line characters   to be replaced with   single spaces   when this value   is read by a   YAML parser.  literal_string: |   This is another   really long string.   It is presented in   YAML "literal"   format.  When a   YAML parser reads   this value, all of   these new-line   characters will be   preserved. --- folded_string: >   This CHANGED   one really long   string.  It   is presented in   YAML "folded"   format.  This will   cause all of the   new-line characters   to be replaced with   single spaces   when this value   is read by a   YAML parser.  literal_string: |   This is another   really long CHANGED string.   It is presented in   YAML "literal"   format.  When a   YAML parser reads   this value, all of   these new-line   characters will be   preserved. c folded_string < "This is one really long string.  It is presented in YAML \"folded\" format.  This will cause all of the new-line characters to be replaced with single spaces when this value is read by a YAML parser." --- > "This CHANGED one really long string.  It is presented in YAML \"folded\" format.  This will cause all of the new-line characters to be replaced with single spaces when this value is read by a YAML parser."  c literal_string < "This is another < really long string. < It is presented in < YAML \"literal\" < format.  When a < YAML parser reads < this value, all of < these new-line < characters will be < preserved." --- > "This is another > really long CHANGED string. > It is presented in > YAML \"literal\" > format.  When a > YAML parser reads > this value, all of > these new-line > characters will be > preserved." # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) --- folded_string: >   This is   one really long   string.  It   is presented in   YAML "folded"   format.  This will   cause all of the   new-line characters   to be replaced with   single spaces   when this value   is read by a   YAML parser.  literal_string: |   This is another   really long string.   It is presented in   YAML "literal"   format.  When a   YAML parser reads   this value, all of   these new-line   characters will be   preserved. --- folded_string: >   This CHANGED   one really long   string.  It   is presented in   YAML "folded"   format.  This will   cause all of the   new-line characters   to be replaced with   single spaces   when this value   is read by a   YAML parser.  literal_string: |   This is another   really long CHANGED string.   It is presented in   YAML "literal"   format.  When a   YAML parser reads   this value, all of   these new-line   characters will be   preserved. c1.0.0.1.0.0 folded_string < "This is one really long string.  It is presented in YAML \"folded\" format.  This will cause all of the new-line characters to be replaced with single spaces when this value is read by a YAML parser." --- > "This CHANGED one really long string.  It is presented in YAML \"folded\" format.  This will cause all of the new-line characters to be replaced with single spaces when this value is read by a YAML parser."  c1.0.1.1.0.1 literal_string < "This is another < really long string. < It is presented in < YAML \"literal\" < format.  When a < YAML parser reads < this value, all of < these new-line < characters will be < preserved." --- > "This is another > really long CHANGED string. > It is presented in > YAML \"literal\" > format.  When a > YAML parser reads > this value, all of > these new-line > characters will be > preserved." # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) a [0] > "zeta"  a [5] > "gamma"  c [6] < "delta" --- > "phi"  d [4] < "delta"  d [8] < "alpha"  d [9] < "theta" # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) --- - 0 - 1 --- - 0 - 1 - 2 a [2] > 2 # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) --- - id: 0   name: zero --- - id: 0   name: zero - id: 1   name: uno a [1] > {"id": 1, "name": "uno"} # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) --- - id: 1   name: uno - id: 0   name: zero --- - id: 0   name: zero - id: 2   name: dos - id: 1   name: uno a [1] > {"id": 2, "name": "dos"} # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) --- - id: 0   name: zero - id: 1   name: uno --- - id: 0   name: zero d [1] < {"id": 1, "name": "uno"} # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) --- - id: 0   name: zero - id: 1   name: uno - id: 2   name: dos --- - id: 1   name: uno - id: 0   name: zero d [2] < {"id": 2, "name": "dos"} # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) --- - id: 1   name: uno - id: 0   name: zero - name: tres --- - id: 0   name: zero - name: dos - id: 1   name: uno a [1] > {"name": "dos"}  d [2] < {"name": "tres"} # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) --- products:   - product: doodad     sku: 0-000-0001-0     availability:       start:         date: 2020-10-10         time: 08:00       stop:         date: 2020-10-29         time: 17:00     dimensions:       width: 5       height: 5       depth: 5       weight: 10   - product: dumdow     sku: 0-000-0002-0     availability:       start:         date: 2020-10-23         time: 08:00       stop:         date: 2020-11-23         time: 17:00     dimensions:       width: 3       height: 3       depth: 3       weight: 27   - product: doohickey     sku: 0-000-0003-0     availability:       start:         date: 2020-08-01         time: 10:00       stop:         date: 2020-09-25         time: 10:00     dimensions:       width: 1       height: 2       depth: 3       weight: 4   - product: widget     sku: 0-000-0004-0     availability:       start:         date: 2020-01-01         time: 12:00       stop:         date: 2020-01-01         time: 16:00     dimensions:       width: 9       height: 10       depth: 1       weight: 4 --- products:   - sku: 0-000-0001-0     availability:       start:         date: 2020-10-10         time: 08:00       stop:         date: 2020-10-29         time: 17:00     dimensions:       width: 5       height: 5       depth: 5       weight: 10   - sku: 0-000-0002-0     availability:       start:         date: 2020-10-23         time: 08:00       stop:         date: 2020-11-23         time: 17:00     dimensions:       width: 4       height: 3       depth: 3       weight: 27   - dimensions:       width: 9       height: 10       depth: 1       weight: 4     sku: 0-000-0004-0     availability:       start:         date: 2020-01-01         time: 12:00       stop:         date: 2020-01-01         time: 16:00   - product: doohickey     availability:       stop:         date: 2020-09-25         time: 10:00       start:         date: 2020-08-01         time: 10:00     dimensions:       weight: 4       width: 1       depth: 3       height: 2 [rules] /products = key  [keys] /products[product=doohickey] = product c products[0] < {"product": "doodad", "sku": "0-000-0001-0", "availability": {"start": {"date": "2020-10-10", "time": "08:00"}, "stop": {"date": "2020-10-29", "time": "17:00"}}, "dimensions": {"width": 5, "height": 5, "depth": 5, "weight": 10}} --- > {"sku": "0-000-0001-0", "availability": {"start": {"date": "2020-10-10", "time": "08:00"}, "stop": {"date": "2020-10-29", "time": "17:00"}}, "dimensions": {"width": 5, "height": 5, "depth": 5, "weight": 10}}  c products[1] < {"product": "dumdow", "sku": "0-000-0002-0", "availability": {"start": {"date": "2020-10-23", "time": "08:00"}, "stop": {"date": "2020-11-23", "time": "17:00"}}, "dimensions": {"width": 3, "height": 3, "depth": 3, "weight": 27}} --- > {"sku": "0-000-0002-0", "availability": {"start": {"date": "2020-10-23", "time": "08:00"}, "stop": {"date": "2020-11-23", "time": "17:00"}}, "dimensions": {"width": 4, "height": 3, "depth": 3, "weight": 27}}  c products[2] < {"product": "doohickey", "sku": "0-000-0003-0", "availability": {"start": {"date": "2020-08-01", "time": "10:00"}, "stop": {"date": "2020-09-25", "time": "10:00"}}, "dimensions": {"width": 1, "height": 2, "depth": 3, "weight": 4}} --- > {"product": "doohickey", "availability": {"stop": {"date": "2020-09-25", "time": "10:00"}, "start": {"date": "2020-08-01", "time": "10:00"}}, "dimensions": {"weight": 4, "width": 1, "depth": 3, "height": 2}}  c products[3] < {"product": "widget", "sku": "0-000-0004-0", "availability": {"start": {"date": "2020-01-01", "time": "12:00"}, "stop": {"date": "2020-01-01", "time": "16:00"}}, "dimensions": {"width": 9, "height": 10, "depth": 1, "weight": 4}} --- > {"dimensions": {"width": 9, "height": 10, "depth": 1, "weight": 4}, "sku": "0-000-0004-0", "availability": {"start": {"date": "2020-01-01", "time": "12:00"}, "stop": {"date": "2020-01-01", "time": "16:00"}}} # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) --- aliases:   - &one One   - &two !tag_two Two   - &three !tag_three Three  hash_one:   key_one: *one   key_two: *two   key_three: *three   *one : *two   *two : *one   *three : *three  hash_two:   key_one: *one   key_two: *two   *one : *two   *two : *one   *three : *three --- aliases:   - &one !tag_one One   - &two Two   - &three !tag_tres Three  hash_one:   key_one: *one   key_two: *two   key_three: *three   *one : *two   *two : *one   *three : *three  hash_two: !example   key_one: *one   key_two: *two   *one : *two   *two : *one   *three : *three c aliases[0] < "One" --- > !tag_one "One"  c aliases[1] < !tag_two "Two" --- > "Two"  c aliases[2] < !tag_three "Three" --- > !tag_tres "Three"  c hash_one.key_one < "One" --- > !tag_one "One"  a hash_one.One !tag_one > "Two"  a hash_one.Two > !tag_one "One"  a hash_one.Three !tag_tres > !tag_tres "Three"  c hash_one.key_two < !tag_two "Two" --- > "Two"  c hash_one.key_three < !tag_three "Three" --- > !tag_tres "Three"  d hash_one.One < !tag_two "Two"  d hash_one.Two !tag_two < "One"  d hash_one.Three !tag_three < !tag_three "Three"  a hash_two !example > {"key_one": "One", "key_two": "Two", "One": "Two", "Two": "One", "Three": "Three"}  d hash_two < {"key_one": "One", "key_two": "Two", "One": "Two", "Two": "One", "Three": "Three"} # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(merged_yaml_content) # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(self.diff_set_defaults) # DEBUG # print("LHS File:  {}".format(lhs_file)) # print("RHS File:  {}".format(rhs_file)) # print("Expected Output:") # print(self.diff_set_defaults) a four > "four"  a three > "three"  a two > "two" d one < "one"  d two < "two"  d four < "four"