# -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. import odoo.tests from odoo.tests.common import BaseCase from odoo.addons.web_editor.models.diff_utils import ( generate_patch, generate_comparison, apply_patch, ) @odoo.tests.tagged("post_install", "-at_install", "html_history") class TestPatchUtils(BaseCase): def test_new_content_add_line(self): initial_content = "

foo

baz

" new_content = "

foo

bar

baz

" patch = generate_patch(new_content, initial_content) # Even if we added content in the new_content, we expect a remove # operation, because the patch would be used to restore the initial # content from the new content. self.assertEqual(patch, "-@3,4") restored_initial_content = apply_patch(new_content, patch) self.assertEqual(restored_initial_content, initial_content) comparison = generate_comparison(new_content, initial_content) self.assertEqual( comparison, "

foo

bar

baz

" ) def test_new_content_remove_line(self): initial_content = "

foo

bar

baz

" new_content = "

foo

baz

" patch = generate_patch(new_content, initial_content) self.assertEqual(patch, "+@2:

bar

") restored_initial_content = apply_patch(new_content, patch) self.assertEqual(restored_initial_content, initial_content) comparison = generate_comparison(new_content, initial_content) self.assertEqual( comparison, "

foo

bar

baz

" ) def test_new_content_replace_line(self): initial_content = "

foo

bar

bor

bir

baz

" new_content = "

foo

buz

baz

" patch = generate_patch(new_content, initial_content) self.assertEqual(patch, "R@3:

bar

bor

bir") restored_initial_content = apply_patch(new_content, patch) self.assertEqual(restored_initial_content, initial_content) comparison = generate_comparison(new_content, initial_content) self.assertEqual( comparison, "

foo

" "

bar

" "

bor

" "

birbuz

" "

baz

", ) def test_new_content_is_falsy(self): initial_content = "

foo

bar

" new_content = "" patch = generate_patch(new_content, initial_content) self.assertEqual(patch, "+@0:

foo

bar

") restored_initial_content = apply_patch(new_content, patch) self.assertEqual(restored_initial_content, initial_content) comparison = generate_comparison(new_content, initial_content) self.assertEqual( comparison, "

foo

bar

" ) def test_new_content_is_equal(self): initial_content = "

foo

bar

" new_content = "

foo

bar

" patch = generate_patch(new_content, initial_content) self.assertEqual(patch, "") restored_initial_content = apply_patch(new_content, patch) self.assertEqual(restored_initial_content, initial_content) initial_content = "" new_content = "" patch = generate_patch(new_content, initial_content) self.assertEqual(patch, "") restored_initial_content = apply_patch(new_content, patch) self.assertEqual(restored_initial_content, initial_content) def test_new_content_multiple_operation(self): initial_content = "

foo

bar

baz

buz

boz

" new_content = ( "

foo

new1new2new3
" "

bar

baz

boz

end

" ) patch = generate_patch(new_content, initial_content) self.assertEqual( patch, """-@3,6 +@10:

buz

-@13,14""", ) restored_initial_content = apply_patch(new_content, patch) self.assertEqual(restored_initial_content, initial_content) comparison = generate_comparison(new_content, initial_content) self.assertEqual( comparison, "

foo

" "
new1" "new2" "new3
" "

bar

baz

buz

" "

boz

end

", ) def test_multiple_revision(self): contents = [ "

foo

bar

", "

foo

", "

fui

baz

", "

fi

boz

", "

something

completely different

", "

foo

boz

buz

", "

buz

", ] patches = [] for i in range(len(contents) - 1): patches.append(generate_patch(contents[i + 1], contents[i])) patches.reverse() reconstruct_content = contents[-1] for patch in patches: reconstruct_content = apply_patch(reconstruct_content, patch) self.assertEqual(reconstruct_content, contents[0]) def test_replace_tag(self): initial_content = "
foo
" new_content = "foo" comparison = generate_comparison(new_content, initial_content) self.assertEqual( comparison, "
foo
" "foo", ) def test_replace_complex(self): initial_content = ( "
foo
" "
bar
" "
baz
" "

---***---

" "
only content change
" "

+++~~~+++

" "
content and tag change
" "

???===???

" "
111
" "
222
" "
333
" ) new_content = ( "foo" "bar" "baz" "

---***---

" "
lorem ipsum
" "

+++~~~+++

" "dolor sit amet" "

???===???

" "
aaa
" "
bbb
" "
ccc
" ) comparison = generate_comparison(new_content, initial_content) self.assertEqual( comparison, "
foo
" "
bar
" "
baz
" "foo" "bar" "baz" "

---***---

" "
only content change" "lorem ipsum
" "

+++~~~+++

" "
content and tag change
" "dolor sit amet" "

???===???

" "
111aaa
" "
222bbb
" "
333ccc
", ) def test_replace_tag_multiline(self): initial_content = ( "
foo
" "bar lorem ipsum dolor" "
baz
" ) new_content = ( "foo" "
bar lorem ipsum dolor
" "baz" ) comparison = generate_comparison(new_content, initial_content) self.assertEqual( comparison, "
foo
" "bar lorem ipsum dolor" "foo" "
baz" "bar lorem ipsum dolor
" "baz", ) def test_replace_nested_divs(self): initial_content = "
A
" new_content = "
B
" comparison = generate_comparison(new_content, initial_content) # This is a trade-off because of the limitation of the current # comparison system : # We can't easily generate comparison when only the tag parameters # changes, because the diff system will not contain the closing tags # in this case. # # This is why we choose to have the comparison below instead of : #
# A #
#
# B #
# # If we need to improve this in the future, we would probably have to # change drastically the comparison system to add a way to parse HTML. self.assertEqual( comparison, "
" "A" "B" "
", ) def test_same_tag_replace_fixer(self): initial_content = "

AB

" new_content = "
X

B

" comparison = generate_comparison(new_content, initial_content) # This is a trade-off, see explanation in test_replace_nested_divs. self.assertEqual( comparison, "
X" "

A" "B

", ) def test_simple_removal(self): initial_content = "

A

" new_content = "
X

A

" comparison = generate_comparison(new_content, initial_content) # This is a trade-off, see explanation in test_replace_nested_divs. self.assertEqual( comparison, "
X

A

", ) def test_simple_addition(self): initial_content = "
X

A

" new_content = "

A

" comparison = generate_comparison(new_content, initial_content) # This is a trade-off, see explanation in test_replace_nested_divs. self.assertEqual( comparison, "
X

A

", ) def test_replace_just_class(self): initial_content = "
A
" new_content = "
A
" comparison = generate_comparison(new_content, initial_content) # This is a trade-off, see explanation in test_replace_nested_divs. self.assertEqual( comparison, "
A
", ) def test_replace_twice_just_class(self): initial_content = ( "
A

abc

D
" ) new_content = "
A

abc

D
" comparison = generate_comparison(new_content, initial_content) # This is a trade-off, see explanation in test_replace_nested_divs. self.assertEqual( comparison, "
A

abc

D
", ) def test_replace_with_just_class(self): initial_content = "

abc

A
" new_content = "

def

A
" comparison = generate_comparison(new_content, initial_content) # This is a trade-off, see explanation in test_replace_nested_divs. self.assertEqual( comparison, "

abcdef

" "
A
", ) def test_replace_class_and_content(self): initial_content = "
A
" new_content = "
B
" comparison = generate_comparison(new_content, initial_content) # This is a trade-off, see explanation in test_replace_nested_divs. self.assertEqual( comparison, "
AB
", ) def test_replace_class_and_deep_content(self): initial_content = "

A

" new_content = "

B

" comparison = generate_comparison(new_content, initial_content) # This is a trade-off, see explanation in test_replace_nested_divs. self.assertEqual( comparison, "

" "AB" "

", )