# test code for the lineinfile module
# (c) 2014, James Cammarata <jcammarata@ansible.com>

# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.

- name: deploy the test file for lineinfile
  copy:
    src: test.txt
    dest: "{{ output_dir }}/test.txt"
  register: result

- name: assert that the test file was deployed
  assert:
    that:
      - result is changed
      - "result.checksum == '5feac65e442c91f557fc90069ce6efc4d346ab51'"
      - "result.state == 'file'"

- name: insert a line at the beginning of the file, and back it up
  lineinfile:
    dest: "{{ output_dir }}/test.txt"
    state: present
    line: "New line at the beginning"
    insertbefore: "BOF"
    backup: yes
  register: result

- name: assert that the line was inserted at the head of the file
  assert:
    that:
      - result is changed
      - "result.msg == 'line added'"
      - "result.backup != ''"

- name: stat the backup file
  stat:
    path: "{{ result.backup }}"
  register: result

- name: assert the backup file matches the previous hash
  assert:
    that:
      - "result.stat.checksum == '5feac65e442c91f557fc90069ce6efc4d346ab51'"

- name: stat the test after the insert at the head
  stat:
    path: "{{ output_dir }}/test.txt"
  register: result

- name: assert test hash is what we expect for the file with the insert at the head
  assert:
    that:
      - "result.stat.checksum == '7eade4042b23b800958fe807b5bfc29f8541ec09'"

- name: insert a line at the end of the file
  lineinfile:
    dest: "{{ output_dir }}/test.txt"
    state: present
    line: "New line at the end"
    insertafter: "EOF"
  register: result

- name: assert that the line was inserted at the end of the file
  assert:
    that:
      - result is changed
      - "result.msg == 'line added'"

- name: stat the test after the insert at the end
  stat:
    path: "{{ output_dir }}/test.txt"
  register: result

- name: assert test checksum matches after the insert at the end
  assert:
    that:
      - "result.stat.checksum == 'fb57af7dc10a1006061b000f1f04c38e4bef50a9'"

- name: insert a line after the first line
  lineinfile:
    dest: "{{ output_dir }}/test.txt"
    state: present
    line: "New line after line 1"
    insertafter: "^This is line 1$"
  register: result

- name: assert that the line was inserted after the first line
  assert:
    that:
      - result is changed
      - "result.msg == 'line added'"

- name: stat the test after insert after the first line
  stat:
    path: "{{ output_dir }}/test.txt"
  register: result

- name: assert test checksum matches after the insert after the first line
  assert:
    that:
      - "result.stat.checksum == '5348da605b1bc93dbadf3a16474cdf22ef975bec'"

- name: insert a line before the last line
  lineinfile:
    dest: "{{ output_dir }}/test.txt"
    state: present
    line: "New line after line 5"
    insertbefore: "^This is line 5$"
  register: result

- name: assert that the line was inserted before the last line
  assert:
    that:
      - result is changed
      - "result.msg == 'line added'"

- name: stat the test after the insert before the last line
  stat:
    path: "{{ output_dir }}/test.txt"
  register: result

- name: assert test checksum matches after the insert before the last line
  assert:
    that:
      - "result.stat.checksum == 'e1cae425403507feea4b55bb30a74decfdd4a23e'"

- name: replace a line with backrefs
  lineinfile:
    dest: "{{ output_dir }}/test.txt"
    state: present
    line: "This is line 3"
    backrefs: yes
    regexp: "^(REF) .* \\1$"
  register: result

- name: assert that the line with backrefs was changed
  assert:
    that:
      - result is changed
      - "result.msg == 'line replaced'"

- name: stat the test after the backref line was replaced
  stat:
    path: "{{ output_dir }}/test.txt"
  register: result

- name: assert test checksum matches after backref line was replaced
  assert:
    that:
      - "result.stat.checksum == '2ccdf45d20298f9eaece73b713648e5489a52444'"

- name: remove the middle line
  lineinfile:
    dest: "{{ output_dir }}/test.txt"
    state: absent
    regexp: "^This is line 3$"
  register: result

- name: assert that the line was removed
  assert:
    that:
      - result is changed
      - "result.msg == '1 line(s) removed'"

- name: stat the test after the middle line was removed
  stat:
    path: "{{ output_dir }}/test.txt"
  register: result

- name: assert test checksum matches after the middle line was removed
  assert:
    that:
      - "result.stat.checksum == 'a6ba6865547c19d4c203c38a35e728d6d1942c75'"

- name: run a validation script that succeeds
  lineinfile:
    dest: "{{ output_dir }}/test.txt"
    state: absent
    regexp: "^This is line 5$"
    validate: "true %s"
  register: result

- name: assert that the file validated after removing a line
  assert:
    that:
      - result is changed
      - "result.msg == '1 line(s) removed'"

- name: stat the test after the validation succeeded
  stat:
    path: "{{ output_dir }}/test.txt"
  register: result

- name: assert test checksum matches after the validation succeeded
  assert:
    that:
      - "result.stat.checksum == '76955a4516a00a38aad8427afc9ee3e361024ba5'"

- name: run a validation script that fails
  lineinfile:
    dest: "{{ output_dir }}/test.txt"
    state: absent
    regexp: "^This is line 1$"
    validate: "/bin/false %s"
  register: result
  ignore_errors: yes

- name: assert that the validate failed
  assert:
    that:
      - "result.failed == true"

- name: stat the test after the validation failed
  stat:
    path: "{{ output_dir }}/test.txt"
  register: result

- name: assert test checksum matches the previous after the validation failed
  assert:
    that:
      - "result.stat.checksum == '76955a4516a00a38aad8427afc9ee3e361024ba5'"

- name: use create=yes
  lineinfile:
    dest: "{{ output_dir }}/new_test.txt"
    create: yes
    insertbefore: BOF
    state: present
    line: "This is a new file"
  register: result

- name: assert that the new file was created
  assert:
    that:
      - result is changed
      - "result.msg == 'line added'"

- name: validate that the newly created file exists
  stat:
    path: "{{ output_dir }}/new_test.txt"
  register: result
  ignore_errors: yes

- name: assert the newly created test checksum matches
  assert:
    that:
      - "result.stat.checksum == '038f10f9e31202451b093163e81e06fbac0c6f3a'"

# Test EOF in cases where file has no newline at EOF
- name: testnoeof deploy the file for lineinfile
  copy:
    src: testnoeof.txt
    dest: "{{ output_dir }}/testnoeof.txt"
  register: result

- name: testnoeof insert a line at the end of the file
  lineinfile:
    dest: "{{ output_dir }}/testnoeof.txt"
    state: present
    line: "New line at the end"
    insertafter: "EOF"
  register: result

- name: testempty assert that the line was inserted at the end of the file
  assert:
    that:
      - result is changed
      - "result.msg == 'line added'"

- name: insert a multiple lines at the end of the file
  lineinfile:
    dest: "{{ output_dir }}/test.txt"
    state: present
    line: "This is a line\nwith \\n character"
    insertafter: "EOF"
  register: result

- name: assert that the multiple lines was inserted
  assert:
    that:
      - result is changed
      - "result.msg == 'line added'"

- name: testnoeof stat the no newline EOF test after the insert at the end
  stat:
    path: "{{ output_dir }}/testnoeof.txt"
  register: result

- name: testnoeof assert test checksum matches after the insert at the end
  assert:
    that:
      - "result.stat.checksum == 'f9af7008e3cb67575ce653d094c79cabebf6e523'"

# Test EOF with empty file to make sure no unnecessary newline is added
- name: testempty deploy the testempty file for lineinfile
  copy:
    src: testempty.txt
    dest: "{{ output_dir }}/testempty.txt"
  register: result

- name: testempty insert a line at the end of the file
  lineinfile:
    dest: "{{ output_dir }}/testempty.txt"
    state: present
    line: "New line at the end"
    insertafter: "EOF"
  register: result

- name: testempty assert that the line was inserted at the end of the file
  assert:
    that:
      - result is changed
      - "result.msg == 'line added'"

- name: testempty stat the test after the insert at the end
  stat:
    path: "{{ output_dir }}/testempty.txt"
  register: result

- name: testempty assert test checksum matches after the insert at the end
  assert:
    that:
      - "result.stat.checksum == 'f440dc65ea9cec3fd496c1479ddf937e1b949412'"

- stat:
    path: "{{ output_dir }}/test.txt"
  register: result

- name: assert test checksum matches after inserting multiple lines
  assert:
    that:
      - "result.stat.checksum == 'bf5b711f8f0509355aaeb9d0d61e3e82337c1365'"

- name: replace a line with backrefs included in the line
  lineinfile:
    dest: "{{ output_dir }}/test.txt"
    state: present
    line: "New \\1 created with the backref"
    backrefs: yes
    regexp: "^This is (line 4)$"
  register: result

- name: assert that the line with backrefs was changed
  assert:
    that:
      - result is changed
      - "result.msg == 'line replaced'"

- name: stat the test after the backref line was replaced
  stat:
    path: "{{ output_dir }}/test.txt"
  register: result

- name: assert test checksum matches after backref line was replaced
  assert:
    that:
      - "result.stat.checksum == '04b7a54d0fb233a4e26c9e625325bb4874841b3c'"

###################################################################
# issue 8535

- name: create a new file for testing quoting issues
  file:
    dest: "{{ output_dir }}/test_quoting.txt"
    state: touch
  register: result

- name: assert the new file was created
  assert:
    that:
    - result is changed

- name: use with_items to add code-like strings to the quoting txt file
  lineinfile:
    dest: "{{ output_dir }}/test_quoting.txt"
    line: "{{ item }}"
    insertbefore: BOF
  with_items:
    - "'foo'"
    - "dotenv.load();"
    - "var dotenv = require('dotenv');"
  register: result

- name: assert the quote test file was modified correctly
  assert:
    that:
      - result.results|length == 3
      - result.results[0] is changed
      - result.results[0].item == "'foo'"
      - result.results[1] is changed
      - result.results[1].item == "dotenv.load();"
      - result.results[2] is changed
      - result.results[2].item == "var dotenv = require('dotenv');"

- name: stat the quote test file
  stat:
    path: "{{ output_dir }}/test_quoting.txt"
  register: result

- name: assert test checksum matches after backref line was replaced
  assert:
    that:
    - "result.stat.checksum == '7dc3cb033c3971e73af0eaed6623d4e71e5743f1'"

- name: insert a line into the quoted file with a single quote
  lineinfile:
    dest: "{{ output_dir }}/test_quoting.txt"
    line: "import g'"
  register: result

- name: assert that the quoted file was changed
  assert:
    that:
    - result is changed

- name: stat the quote test file
  stat:
    path: "{{ output_dir }}/test_quoting.txt"
  register: result

- name: assert test checksum matches after backref line was replaced
  assert:
    that:
    - "result.stat.checksum == '73b271c2cc1cef5663713bc0f00444b4bf9f4543'"

- name: insert a line into the quoted file with many double quotation strings
  lineinfile:
    dest: "{{ output_dir }}/test_quoting.txt"
    line: "\"quote\" and \"unquote\""
  register: result

- name: assert that the quoted file was changed
  assert:
    that:
    - result is changed

- name: stat the quote test file
  stat:
    path: "{{ output_dir }}/test_quoting.txt"
  register: result

- name: assert test checksum matches after backref line was replaced
  assert:
    that:
    - "result.stat.checksum == 'b10ab2a3c3b6492680c8d0b1d6f35aa6b8f9e731'"

###################################################################
# Issue 28721

- name: Deploy the testmultiple file
  copy:
    src: testmultiple.txt
    dest: "{{ output_dir }}/testmultiple.txt"
  register: result

- name: Assert that the testmultiple file was deployed
  assert:
    that:
      - result is changed
      - result.checksum == '3e0090a34fb641f3c01e9011546ff586260ea0ea'
      - result.state == 'file'

# Test insertafter
- name: Write the same line to a file inserted after different lines
  lineinfile:
    path: "{{ output_dir }}/testmultiple.txt"
    insertafter: "{{ item.regex }}"
    line: "{{ item.replace }}"
  register: _multitest_1
  with_items: "{{ test_regexp }}"

- name: Do the same thing again to check for changes
  lineinfile:
    path: "{{ output_dir }}/testmultiple.txt"
    insertafter: "{{ item.regex }}"
    line: "{{ item.replace }}"
  register: _multitest_2
  with_items: "{{ test_regexp }}"

- name: Assert that the file was changed the first time but not the second time
  assert:
    that:
      - item.0 is changed
      - item.1 is not changed
  with_together:
    - "{{ _multitest_1.results }}"
    - "{{ _multitest_2.results }}"

- name: Stat the insertafter file
  stat:
    path: "{{ output_dir }}/testmultiple.txt"
  register: result

- name: Assert that the insertafter file matches expected checksum
  assert:
    that:
      - result.stat.checksum == '282fedf460b3ed7357667a9c8b457ec67b53b6ea'

# Test insertbefore
- name: Write the same line to a file inserted before different lines
  lineinfile:
    path: "{{ output_dir }}/testmultiple.txt"
    insertbefore: "{{ item.regex }}"
    line: "{{ item.replace }}"
  register: _multitest_3
  with_items: "{{ test_regexp }}"

- name: Do the same thing again to check for changes
  lineinfile:
    path: "{{ output_dir }}/testmultiple.txt"
    insertbefore: "{{ item.regex }}"
    line: "{{ item.replace }}"
  register: _multitest_4
  with_items: "{{ test_regexp }}"

- name: Assert that the file was changed the first time but not the second time
  assert:
    that:
      - item.0 is changed
      - item.1 is not changed
  with_together:
    - "{{ _multitest_3.results }}"
    - "{{ _multitest_4.results }}"

- name: Stat the insertbefore file
  stat:
    path: "{{ output_dir }}/testmultiple.txt"
  register: result

- name: Assert that the insertbefore file matches expected checksum
  assert:
    that:
      - result.stat.checksum == 'a8452bb3643be8d18ba3fc212632b1633bd9f885'

###################################################################
# Issue 36156
# Test insertbefore and insertafter with regexp

- name: Deploy the test.conf file
  copy:
    src: test.conf
    dest: "{{ output_dir }}/test.conf"
  register: result

- name: Assert that the test.conf file was deployed
  assert:
    that:
      - result is changed
      - result.checksum == '6037f13e419b132eb3fd20a89e60c6c87a6add38'
      - result.state == 'file'

# Test instertafter
- name: Insert lines after with regexp
  lineinfile:
    path: "{{ output_dir }}/test.conf"
    regexp: "{{ item.regexp }}"
    line: "{{ item.line }}"
    insertafter: "{{ item.after }}"
  with_items: "{{ test_befaf_regexp }}"
  register: _multitest_5

- name: Do the same thing again and check for changes
  lineinfile:
    path: "{{ output_dir }}/test.conf"
    regexp: "{{ item.regexp }}"
    line: "{{ item.line }}"
    insertafter: "{{ item.after }}"
  with_items: "{{ test_befaf_regexp }}"
  register: _multitest_6

- name: Assert that the file was changed the first time but not the second time
  assert:
    that:
      - item.0 is changed
      - item.1 is not changed
  with_together:
    - "{{ _multitest_5.results }}"
    - "{{ _multitest_6.results }}"

- name: Stat the file
  stat:
    path: "{{ output_dir }}/test.conf"
  register: result

- name: Assert that the file contents match what is expected
  assert:
    that:
      - result.stat.checksum == '06e2c456e5028dd7bcd0b117b5927a1139458c82'

- name: Do the same thing a third time without regexp and check for changes
  lineinfile:
    path: "{{ output_dir }}/test.conf"
    line: "{{ item.line }}"
    insertafter: "{{ item.after }}"
  with_items: "{{ test_befaf_regexp }}"
  register: _multitest_7

- name: Stat the file
  stat:
    path: "{{ output_dir }}/test.conf"
  register: result

- name: Assert that the file was changed when no regexp was provided
  assert:
    that:
      - item is changed
  with_items: "{{ _multitest_7.results }}"

- name: Stat the file
  stat:
    path: "{{ output_dir }}/test.conf"
  register: result

- name: Assert that the file contents match what is expected
  assert:
    that:
      - result.stat.checksum == '5bf50f3d74afd20de4010ca5c04bc7037b062d30'

# Test insertbefore
- name: Deploy the test.conf file
  copy:
    src: test.conf
    dest: "{{ output_dir }}/test.conf"
  register: result

- name: Assert that the test.conf file was deployed
  assert:
    that:
      - result is changed
      - result.checksum == '6037f13e419b132eb3fd20a89e60c6c87a6add38'
      - result.state == 'file'

- name: Insert lines before with regexp
  lineinfile:
    path: "{{ output_dir }}/test.conf"
    regexp: "{{ item.regexp }}"
    line: "{{ item.line }}"
    insertbefore: "{{ item.before }}"
  with_items: "{{ test_befaf_regexp }}"
  register: _multitest_8

- name: Do the same thing again and check for changes
  lineinfile:
    path: "{{ output_dir }}/test.conf"
    regexp: "{{ item.regexp }}"
    line: "{{ item.line }}"
    insertbefore: "{{ item.before }}"
  with_items: "{{ test_befaf_regexp }}"
  register: _multitest_9

- name: Assert that the file was changed the first time but not the second time
  assert:
    that:
      - item.0 is changed
      - item.1 is not changed
  with_together:
    - "{{ _multitest_8.results }}"
    - "{{ _multitest_9.results }}"

- name: Stat the file
  stat:
    path: "{{ output_dir }}/test.conf"
  register: result

- name: Assert that the file contents match what is expected
  assert:
    that:
      - result.stat.checksum == 'c3be9438a07c44d4c256cebfcdbca15a15b1db91'

- name: Do the same thing a third time without regexp and check for changes
  lineinfile:
    path: "{{ output_dir }}/test.conf"
    line: "{{ item.line }}"
    insertbefore: "{{ item.before }}"
  with_items: "{{ test_befaf_regexp }}"
  register: _multitest_10

- name: Stat the file
  stat:
    path: "{{ output_dir }}/test.conf"
  register: result

- name: Assert that the file was changed when no regexp was provided
  assert:
    that:
      - item is changed
  with_items: "{{ _multitest_10.results }}"

- name: Stat the file
  stat:
    path: "{{ output_dir }}/test.conf"
  register: result

- name: Assert that the file contents match what is expected
  assert:
    that:
      - result.stat.checksum == 'eca8d8ea089d4ea57a3b87d4091599ca8b60dfd2'
