def write_to_file():
	fakefile = FakeFile()

	staticdiffmodel = _make_static_diffmodel()
	old_static_lines = list( ln.clone() for ln in staticdiffmodel.get_lines() )

	editable = EditableDiffModel( staticdiffmodel )

	# Make several overlapping changes, including a deletion
	editable.edit_lines( 0, 2, directions.RIGHT,
		( "edited 1a", "edited 2a", "edited 3a" ) )

	editable.edit_lines( 1, 3, directions.RIGHT,
		( "edited 2b", "edited 3b", "edited 4b" ) )

	editable.delete_lines( 1, 1, directions.RIGHT )

	editable.edit_lines( 2, 4, directions.RIGHT,
		( "edited 3c", "edited 4c", "edited 5c" ) )

	editable.write_to_file( fakefile, directions.RIGHT )

	assert_strings_equal( fakefile.txt,
		  "edited 1a\n"
		+ "edited 3c\n"
		+ "edited 4c\n"
		+ "edited 5c\n"
		+ "line 6 here\n"
		+ "line 7 here\n"
		+ "line 8 here\n"
		+ "line 9 here\n"
		+ "line 10 here\n"
		)

	assert_lines_lists_equal( old_static_lines, staticdiffmodel.get_lines() )
def edit_doesnt_touch():
	staticdiffmodel = _make_static_diffmodel()

	editable = EditableDiffModel( staticdiffmodel )

	# Change 3 lines
	editable.edit_lines( 1, 3, directions.RIGHT,
		( "edited 2", "edited 3", "edited 4" ) )

	# Just ask for line 9
	lines = editable.get_lines( 9, 10 )
	assert( len( lines ) == 1 )

	assert_strings_equal( lines[0].left, "previous 10" )
	assert_strings_equal( lines[0].right, "line 10 here" )
	assert( lines[0].status == difflinetypes.DIFFERENT )
	assert( lines[0].left_edited == False )
	assert( lines[0].right_edited == False )

	ln = editable.get_line( 8 )
	assert_strings_equal( ln.left, "line 9 here" )
	assert_strings_equal( ln.right, "line 9 here" )
	assert( ln.status == difflinetypes.IDENTICAL )
	assert( ln.left_edited == False )
	assert( ln.right_edited == False )
def add_lines_spanning():
	"""If an add overlaps the entire region we asking for,
	we still calculate the right answer."""

	staticdiffmodel = _make_static_diffmodel()
	editable = EditableDiffModel( staticdiffmodel )

	editable.add_lines( 1, directions.RIGHT,
		[
		"new line 1a",
		"new line 1b",
		"new line 1c",
		"new line 1d",
		] )

	# Get some lines containing the add
	lines = editable.get_lines( 2, 4 )
	assert( len( lines ) == 2 )

	ln = lines[0]
	assert_strings_equal( ln.left, None )
	assert_strings_equal( ln.right, "new line 1b" )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == False )
	assert( ln.right_edited == True )
	assert( ln == editable.get_line( 2 ) ) # Sanity for get_line

	ln = lines[1]
	assert_strings_equal( ln.left, None )
	assert_strings_equal( ln.right, "new line 1c" )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == False )
	assert( ln.right_edited == True )
	assert( ln == editable.get_line( 3 ) ) # Sanity for get_line
def empty_file():

	file1 = [
	]

	diff = [
		"--- test/file1.txt	2009-03-28 15:18:52.000000000 +0000\n",
		"+++ test/file2.txt	2009-03-28 15:19:28.000000000 +0000\n",
		"@@ -0,0 +1,1 @@\n",
		"+line 1 here\n",
		"+line 2 here\n",
	]

	unifieddiffparser = UnifiedDiffParser( file1, diff )
	diffmodel = DiffModel( unifieddiffparser )

	lines = diffmodel.get_lines()

	assert( len( lines ) == 2 )

	assert_strings_equal( lines[0].left,  None )
	assert_strings_equal( lines[0].right, "line 1 here" )
	assert( lines[0].status == difflinetypes.ADD )

	assert_strings_equal( lines[1].left,  None )
	assert_strings_equal( lines[1].right, "line 2 here" )
	assert( lines[1].status == difflinetypes.ADD )
def just_differences():
	file1 = [
		"line 1 here\n",
		"line 2 here\n",
	]

	diff = [
		"--- test/file1.txt	2009-03-22 21:42:38.000000000 +0000\n",
		"+++ test/file2.txt	2009-03-22 21:53:26.000000000 +0000\n",
		"@@ -1,2 +1,2 @@\n",
		"-line 1 here\n",
		"-line 2 here\n",
		"+line 1 here different\n",
		"+line 2 here different\n",
	]

	unifieddiffparser = UnifiedDiffParser( file1, diff )
	diffmodel = DiffModel( unifieddiffparser )

	lines = diffmodel.get_lines()

	assert_strings_equal( lines[0].left,  "line 1 here" )
	assert_strings_equal( lines[0].right, "line 1 here different" )
	assert( lines[0].status == difflinetypes.DIFFERENT )

	assert_strings_equal( lines[1].left,  "line 2 here" )
	assert_strings_equal( lines[1].right, "line 2 here different" )
	assert( lines[1].status == difflinetypes.DIFFERENT )
def add_lines_after_overlapping():
	"""The lines after an add are shifted down, even when the adds are overlapping."""

	staticdiffmodel = _make_static_diffmodel()
	editable = EditableDiffModel( staticdiffmodel )

	editable.add_lines( 2, directions.LEFT, ["new line 2a", "new line 2c"] )
	editable.add_lines( 3, directions.LEFT, ["new line 2b"] )

	# Get some lines after the add
	lines = editable.get_lines( 6, 8 )

	assert( len( lines ) == 2 )

	ln = lines[0]
	assert_strings_equal( ln.left, "line 4 here" )
	assert_strings_equal( ln.right, "line 4 here" )
	assert( ln.status == difflinetypes.IDENTICAL )
	assert( ln.left_edited == False )
	assert( ln.right_edited == False )
	assert( ln == editable.get_line( 6 ) ) # Sanity for get_line

	ln = lines[1]
	assert_strings_equal( ln.left, "line 5 here" )
	assert_strings_equal( ln.right, "line 5 here different" )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == False )
	assert( ln.right_edited == False )
	assert( ln == editable.get_line( 7 ) ) # Sanity for get_line
def write_to_file_no_changes():
	fakefile = FakeFile()

	staticdiffmodel = _make_static_diffmodel()
	editable = EditableDiffModel( staticdiffmodel )

	editable.write_to_file( fakefile, directions.LEFT )

	assert_strings_equal( fakefile.txt,
		  "line 1 here\n"
		+ "line 2 here\n"
		+ "line 3 here\n"
		+ "line 4 here\n"
		+ "line 5 here\n"
		+ "line 6 here\n"
		+ "line 7 here\n"
		+ "line 8 here\n"
		+ "line 9 here\n"
		+ "previous 10\n"
		)
def add_at_beginning():
	staticdiffmodel = _make_static_diffmodel()
	old_static_lines = list( ln.clone() for ln in staticdiffmodel.get_lines() )

	editable = EditableDiffModel( staticdiffmodel )

	# Make an add at the beginning of the file
	editable.add_lines( 0, directions.RIGHT,
		( [ "Added 0a", "Added 0b"] ) )

	lines = editable.get_lines( 0, 3 )
	assert( len( lines ) == 3 )

	ln = lines[0]
	assert_strings_equal( ln.left, None )
	assert_strings_equal( ln.right, "Added 0a" )

	ln = lines[1]
	assert_strings_equal( ln.left, None )
	assert_strings_equal( ln.right, "Added 0b" )
def identical():
	file1 = [
		"line 1 here\n",
		"line 2 here\n",
	]

	diff = []

	unifieddiffparser = UnifiedDiffParser( file1, diff )
	diffmodel = DiffModel( unifieddiffparser )

	lines = diffmodel.get_lines()

	assert_strings_equal( lines[0].left,  "line 1 here" )
	assert_strings_equal( lines[0].right, "line 1 here" )
	assert( lines[0].status == difflinetypes.IDENTICAL )

	assert_strings_equal( lines[1].left,  "line 2 here" )
	assert_strings_equal( lines[1].right, "line 2 here" )
	assert( lines[1].status == difflinetypes.IDENTICAL )
def edit_starts_before():
	staticdiffmodel = _make_static_diffmodel()

	editable = EditableDiffModel( staticdiffmodel )

	# Change 3 lines
	editable.edit_lines( 6, 9, directions.RIGHT,
		( "edited 7", "edited 8", "edited 9", "edited 10" ) )

	# Just ask for lines 8 and 9
	lines = editable.get_lines( 8 )
	assert( len( lines ) == 2 )

	assert_strings_equal( lines[0].left, "line 9 here" )
	assert_strings_equal( lines[0].right, "edited 9" )
	assert( lines[0].status == difflinetypes.DIFFERENT )
	assert( lines[0].left_edited == False )
	assert( lines[0].right_edited == True )

	assert_strings_equal( lines[1].left, "previous 10" )
	assert_strings_equal( lines[1].right, "edited 10" )
	assert( lines[1].status == difflinetypes.DIFFERENT )
	assert( lines[1].left_edited == False )
	assert( lines[1].right_edited == True )
def edit_ends_after():
	staticdiffmodel = _make_static_diffmodel()

	editable = EditableDiffModel( staticdiffmodel )

	# Change 3 lines
	editable.edit_lines( 6, 9, directions.RIGHT,
		( "edited 7", "edited 8", "edited 9", "edited 10" ) )

	# Just ask for lines 6 and 7
	lines = editable.get_lines( 5, 7 )
	assert( len( lines ) == 2 )

	assert_strings_equal( lines[0].left, "line 6 here" )
	assert_strings_equal( lines[0].right, "line 6 here" )
	assert( lines[0].status == difflinetypes.IDENTICAL )
	assert( lines[0].left_edited == False )
	assert( lines[0].right_edited == False )

	assert_strings_equal( lines[1].left, "line 7 here" )
	assert_strings_equal( lines[1].right, "edited 7" )
	assert( lines[1].status == difflinetypes.DIFFERENT )
	assert( lines[1].left_edited == False )
	assert( lines[1].right_edited == True )
def multiple_hunks_no_deletions_or_additions():
	file1 = []
	for i in range( 1, 41 ):
		file1.append( "line %d here\n" % i )

	diff = [
		"--- test/file1.txt	2009-03-28 00:34:14.000000000 +0000\n",
		"+++ test/file2.txt	2009-03-28 00:34:33.000000000 +0000\n",
		"@@ -1,5 +1,5 @@\n",
		" line 1 here\n",
		"-line 2 here\n",
		"+line 2 here different\n",
		" line 3 here\n",
		" line 4 here\n",
		" line 5 here\n",
		"@@ -36,5 +36,5 @@\n",
		" line 36 here\n",
		" line 37 here\n",
		" line 38 here\n",
		"-line 39 here\n",
		"+line 39 here different\n",
		" line 40 here\n",
	]

	unifieddiffparser = UnifiedDiffParser( file1, diff )
	diffmodel = DiffModel( unifieddiffparser )

	lines = diffmodel.get_lines()

	assert_strings_equal( lines[0].left,  "line 1 here" )
	assert_strings_equal( lines[0].right, "line 1 here" )
	assert( lines[0].status == difflinetypes.IDENTICAL )

	assert_strings_equal( lines[1].left,  "line 2 here" )
	assert_strings_equal( lines[1].right, "line 2 here different" )
	assert( lines[1].status == difflinetypes.DIFFERENT )

	for i in range( 3, 39 ):
		assert_strings_equal( lines[i-1].left,  "line %d here" % i )
		assert_strings_equal( lines[i-1].right, "line %d here" % i )
		assert( lines[i-1].status == difflinetypes.IDENTICAL )

	assert_strings_equal( lines[38].left,  "line 39 here" )
	assert_strings_equal( lines[38].right, "line 39 here different" )
	assert( lines[38].status == difflinetypes.DIFFERENT )

	assert_strings_equal( lines[39].left,  "line 40 here" )
	assert_strings_equal( lines[39].right, "line 40 here" )
	assert( lines[39].status == difflinetypes.IDENTICAL )
def add_lines_ask_for_all():
	"""If we ask for all the lines after adding some, we get
	them correctly."""

	staticdiffmodel = _make_static_diffmodel()
	editable = EditableDiffModel( staticdiffmodel )

	editable.add_lines( 1, directions.RIGHT,
		[
		"new line 1a",
		"new line 1b",
		"new line 1c",
		"new line 1d",
		] )

	editable.add_lines( 3, directions.LEFT,
		[
		"new line 1bi",
		"new line 1bii",
		] )

	# Get some lines containing the add
	lines = editable.get_lines()
	assert( len( lines ) == 16 )

	ln = lines[0]
	assert_strings_equal( ln.left, "line 1 here" )
	assert_strings_equal( ln.right, "line 1 here" )

	ln = lines[1]
	assert_strings_equal( ln.left, None )
	assert_strings_equal( ln.right, "new line 1a" )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == False )
	assert( ln.right_edited == True )

	ln = lines[2]
	assert_strings_equal( ln.left, None )
	assert_strings_equal( ln.right, "new line 1b" )

	ln = lines[3]
	assert_strings_equal( ln.left, "new line 1bi" )
	assert_strings_equal( ln.right, None )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == True )
	assert( ln.right_edited == False )

	ln = lines[4]
	assert_strings_equal( ln.left, "new line 1bii" )
	assert_strings_equal( ln.right, None )

	ln = lines[5]
	assert_strings_equal( ln.left, None )
	assert_strings_equal( ln.right, "new line 1c" )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == False )
	assert( ln.right_edited == True )

	ln = lines[6]
	assert_strings_equal( ln.left, None )
	assert_strings_equal( ln.right, "new line 1d" )

	ln = lines[7]
	assert_strings_equal( ln.left, "line 2 here" )
	assert_strings_equal( ln.right, "line 2 here" )

	ln = lines[8]
	assert_strings_equal( ln.left, "line 3 here" )
	assert_strings_equal( ln.right, "line 3 here" )

	ln = lines[9]
	assert_strings_equal( ln.left, "line 4 here" )
	assert_strings_equal( ln.right, "line 4 here" )
def edit_doesnt_change_anything():
	staticdiffmodel = _make_static_diffmodel()
	old_static_lines = list( ln.clone() for ln in staticdiffmodel.get_lines() )

	editable = EditableDiffModel( staticdiffmodel )

	# Make a change that actually doesn't change any lines
	editable.edit_lines( 0, 2, directions.LEFT,
		[ "line 1 here", "line 2 here", "line 3 here" ] )

	# Ask for lines 1 to 3
	lines = editable.get_lines( 0, 3 )
	assert( len( lines ) == 3 )

	assert_strings_equal( lines[0].left, "line 1 here" )
	assert_strings_equal( lines[0].right, "line 1 here" )
	assert( lines[0].status == difflinetypes.IDENTICAL )
	assert( lines[0].left_edited == False )
	assert( lines[0].right_edited == False )

	assert_strings_equal( lines[1].left, "line 2 here" )
	assert_strings_equal( lines[1].right, "line 2 here" )
	assert( lines[1].status == difflinetypes.IDENTICAL )
	assert( lines[1].left_edited == False )
	assert( lines[1].right_edited == False )

	assert_strings_equal( lines[2].left, "line 3 here" )
	assert_strings_equal( lines[2].right, "line 3 here" )
	assert( lines[2].status == difflinetypes.IDENTICAL )
	assert( lines[2].left_edited == False )
	assert( lines[2].right_edited == False )

	assert_lines_lists_equal( old_static_lines, staticdiffmodel.get_lines() )
def removed_at_beginning():

	file1 = [
		"line 1 here\n",
		"line 2 here\n",
		"line 3 here\n",
		"line 4 here\n",
	]

	diff = [
		"--- test/file1.txt	2009-03-28 20:32:36.000000000 +0000\n",
		"+++ test/file2.txt	2009-03-28 20:32:41.000000000 +0000\n",
		"@@ -1,4 +1,2 @@\n",
		"-line 1 here\n",
		"-line 2 here\n",
		" line 3 here\n",
		" line 4 here\n",
	]

	unifieddiffparser = UnifiedDiffParser( file1, diff )
	diffmodel = DiffModel( unifieddiffparser )

	lines = diffmodel.get_lines()

	assert_strings_equal( lines[0].left, "line 1 here" )
	assert( lines[0].right is None )
	assert( lines[0].status == difflinetypes.REMOVE )

	assert_strings_equal( lines[1].left, "line 2 here" )
	assert( lines[1].right is None )
	assert( lines[1].status == difflinetypes.REMOVE )

	assert_strings_equal( lines[2].left, "line 3 here" )
	assert_strings_equal( lines[2].right, "line 3 here" )
	assert( lines[2].status == difflinetypes.IDENTICAL )

	assert_strings_equal( lines[3].left, "line 4 here" )
	assert_strings_equal( lines[3].right, "line 4 here" )
	assert( lines[3].status == difflinetypes.IDENTICAL )
def edit_both_sides():
	staticdiffmodel = _make_static_diffmodel()
	old_static_lines = list( ln.clone() for ln in staticdiffmodel.get_lines() )

	editable = EditableDiffModel( staticdiffmodel )

	# Change 3 lines on left sides
	editable.edit_lines( 7, 9, directions.LEFT,
		( "edited 8", "edited 9", "edited 10" ) )

	# and 4 lines (overlapping) on right
	editable.edit_lines( 6, 9, directions.RIGHT,
		( "edited 7", "edited 8 r", "edited 9", "edited 10 r" ) )

	lines = editable.get_lines()

	# The line before is unchanged
	assert_strings_equal( lines[6].left, "line 7 here" )
	assert_strings_equal( lines[6].right, "edited 7" )
	assert( lines[6].status == difflinetypes.DIFFERENT )
	assert( lines[6].left_edited == False )
	assert( lines[6].right_edited == True )

	# The relevant lines have been changed
	assert_strings_equal( lines[7].left, "edited 8" )
	assert_strings_equal( lines[7].right, "edited 8 r" )
	assert( lines[7].status == difflinetypes.DIFFERENT )
	assert( lines[7].left_edited == True )
	assert( lines[7].right_edited == True )

	assert_strings_equal( lines[8].left, "edited 9" )
	assert_strings_equal( lines[8].right, "edited 9" )
	assert( lines[8].status == difflinetypes.IDENTICAL )
	assert( lines[8].left_edited == True )
	assert( lines[8].right_edited == True )

	assert_strings_equal( lines[9].left, "edited 10" )
	assert_strings_equal( lines[9].right, "edited 10 r" )
	assert( lines[9].status == difflinetypes.DIFFERENT )
	assert( lines[9].left_edited == True )
	assert( lines[9].right_edited == True )

	# The underlying diffmodel has not been altered
	assert_lines_lists_equal( old_static_lines, staticdiffmodel.get_lines() )
def edit_line():
	staticdiffmodel = _make_static_diffmodel()
	old_static_lines = list( ln.clone() for ln in staticdiffmodel.get_lines() )

	editable = EditableDiffModel( staticdiffmodel )

	# Change one line
	editable.edit_lines( 3, 3, directions.RIGHT, ( "edited", ) )

	# The line before is unchanged
	ln = editable.get_line( 2 )
	assert_strings_equal( ln.left, "line 3 here" )
	assert_strings_equal( ln.right, "line 3 here" )
	assert( ln.status == difflinetypes.IDENTICAL )
	assert( ln.left_edited == False )
	assert( ln.right_edited == False )

	# The line itself is changed, and marked as EDITED
	ln = editable.get_line( 3 )
	assert_strings_equal( ln.left, "line 4 here" )
	assert_strings_equal( ln.right, "edited" )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == False )
	assert( ln.right_edited == True )

	# The line after is unchanged
	ln = editable.get_line( 4 )
	assert_strings_equal( ln.left, "line 5 here" )
	assert_strings_equal( ln.right, "line 5 here different" )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == False )
	assert( ln.right_edited == False )

	# The underlying diffmodel has not been altered
	assert_lines_lists_equal( old_static_lines, staticdiffmodel.get_lines() )
def several_edits():
	staticdiffmodel = _make_static_diffmodel()
	old_static_lines = list( ln.clone() for ln in staticdiffmodel.get_lines() )

	editable = EditableDiffModel( staticdiffmodel )

	# Make several overlapping changes
	editable.edit_lines( 0, 2, directions.RIGHT,
		( "edited 1a", "edited 2a", "edited 3a" ) )

	editable.edit_lines( 1, 3, directions.RIGHT,
		( "edited 2b", "edited 3b", "edited 4b" ) )

	editable.edit_lines( 2, 4, directions.RIGHT,
		( "edited 3c", "edited 4c", "edited 5c" ) )

	# Ask for lines 1 to 4
	lines = editable.get_lines( 0, 4 )
	assert( len( lines ) == 4 )

	assert_strings_equal( lines[0].left, "line 1 here" )
	assert_strings_equal( lines[0].right, "edited 1a" )
	assert( lines[0].status == difflinetypes.DIFFERENT )
	assert( lines[0].left_edited == False )
	assert( lines[0].right_edited == True )

	assert_strings_equal( lines[1].left, "line 2 here" )
	assert_strings_equal( lines[1].right, "edited 2b" )
	assert( lines[1].status == difflinetypes.DIFFERENT )
	assert( lines[1].left_edited == False )
	assert( lines[1].right_edited == True )

	assert_strings_equal( lines[2].left, "line 3 here" )
	assert_strings_equal( lines[2].right, "edited 3c" )
	assert( lines[2].status == difflinetypes.DIFFERENT )
	assert( lines[2].left_edited == False )
	assert( lines[2].right_edited == True )

	assert_strings_equal( lines[3].left, "line 4 here" )
	assert_strings_equal( lines[3].right, "edited 4c" )
	assert( lines[3].status == difflinetypes.DIFFERENT )
	assert( lines[3].left_edited == False )
	assert( lines[3].right_edited == True )

	assert_lines_lists_equal( old_static_lines, staticdiffmodel.get_lines() )
def add_lines_before():
	"""The lines before an add are unaffected by it."""

	staticdiffmodel = _make_static_diffmodel()
	editable = EditableDiffModel( staticdiffmodel )

	editable.add_lines( 3, directions.LEFT, ["new line 3a", "new line 3b"] )
	editable.add_lines( 6, directions.LEFT, ["new line 4a", "new line 4b"] )

	# Get some lines before the add
	lines = editable.get_lines( 0, 3 )
	assert( len( lines ) == 3 )

	ln = lines[0]
	assert_strings_equal( ln.left, "line 1 here" )
	assert_strings_equal( ln.right, "line 1 here" )
	assert( ln.status == difflinetypes.IDENTICAL )
	assert( ln.left_edited == False )
	assert( ln.right_edited == False )
	assert( ln == editable.get_line( 0 ) ) # Sanity for get_line

	ln = lines[1]
	assert_strings_equal( ln.left, "line 2 here" )
	assert_strings_equal( ln.right, "line 2 here" )
	assert( ln.status == difflinetypes.IDENTICAL )
	assert( ln.left_edited == False )
	assert( ln.right_edited == False )
	assert( ln == editable.get_line( 1 ) ) # Sanity for get_line

	ln = lines[2]
	assert_strings_equal( ln.left, "line 3 here" )
	assert_strings_equal( ln.right, "line 3 here" )
	assert( ln.status == difflinetypes.IDENTICAL )
	assert( ln.left_edited == False )
	assert( ln.right_edited == False )
	assert( ln == editable.get_line( 2 ) ) # Sanity for get_line
def delete_lines_backwards():
	staticdiffmodel = _make_static_diffmodel()
	old_static_lines = list( ln.clone() for ln in staticdiffmodel.get_lines() )

	editable = EditableDiffModel( staticdiffmodel )

	editable.delete_lines( 2, 1, directions.RIGHT )

	# Ask for lines 1 to 4
	lines = editable.get_lines( 0, 4 )
	assert( len( lines ) == 4 )

	ln = lines[0]
	assert_strings_equal( ln.left, "line 1 here" )
	assert_strings_equal( ln.right, "line 1 here" )
	assert( ln.status == difflinetypes.IDENTICAL )
	assert( ln.left_edited == False )
	assert( ln.right_edited == False )

	ln = lines[1]
	assert_strings_equal( ln.left, "line 2 here" )
	assert_strings_equal( ln.right, None )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == False )
	assert( ln.right_edited == True )

	ln = lines[2]
	assert_strings_equal( ln.left, "line 3 here" )
	assert_strings_equal( ln.right, None )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == False )
	assert( ln.right_edited == True )

	ln = lines[3]
	assert_strings_equal( ln.left, "line 4 here" )
	assert_strings_equal( ln.right, "line 4 here" )
	assert( ln.status == difflinetypes.IDENTICAL )
	assert( ln.left_edited == False )
	assert( ln.right_edited == False )

	assert_lines_lists_equal( old_static_lines, staticdiffmodel.get_lines() )
def delete_line_plus_edits():

	staticdiffmodel = _make_static_diffmodel()
	old_static_lines = list( ln.clone() for ln in staticdiffmodel.get_lines() )

	editable = EditableDiffModel( staticdiffmodel )

	# Make several overlapping changes, including a deletion
	editable.edit_lines( 0, 2, directions.RIGHT,
		( "edited 1a", "edited 2a", "edited 3a" ) )

	editable.edit_lines( 1, 3, directions.RIGHT,
		( "edited 2b", "edited 3b", "edited 4b" ) )

	editable.delete_lines( 1, 1, directions.RIGHT )

	editable.edit_lines( 2, 4, directions.RIGHT,
		( "edited 3c", "edited 4c", "edited 5c" ) )

	# Ask for lines 1 to 3
	lines = editable.get_lines( 0, 3 )
	assert( len( lines ) == 3 )

	ln = lines[0]
	assert_strings_equal( ln.left, "line 1 here" )
	assert_strings_equal( ln.right, "edited 1a" )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == False )
	assert( ln.right_edited == True )

	ln = lines[1]
	assert_strings_equal( ln.left, "line 2 here" )
	assert_strings_equal( ln.right, None )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == False )
	assert( ln.right_edited == True )

	ln = lines[2]
	assert_strings_equal( ln.left, "line 3 here" )
	assert_strings_equal( ln.right, "edited 3c" )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == False )
	assert( ln.right_edited == True )

	assert_lines_lists_equal( old_static_lines, staticdiffmodel.get_lines() )
def edit_after_delete():

	staticdiffmodel = _make_static_diffmodel()
	old_static_lines = list( ln.clone() for ln in staticdiffmodel.get_lines() )

	editable = EditableDiffModel( staticdiffmodel )

	# Delete then edit
	editable.delete_lines( 1, 1, directions.RIGHT )

	editable.edit_lines( 2, 4, directions.RIGHT,
		( "edited 3c", "edited 4c", "edited 5c" ) )

	# Ask for lines 1 to 3
	lines = editable.get_lines( 0, 3 )
	assert( len( lines ) == 3 )

	ln = lines[0]
	assert_strings_equal( ln.left, "line 1 here" )
	assert_strings_equal( ln.right, "line 1 here" )
	assert( ln.status == difflinetypes.IDENTICAL )
	assert( ln.left_edited == False )
	assert( ln.right_edited == False )

	ln = lines[1]
	assert_strings_equal( ln.left, "line 2 here" )
	assert_strings_equal( ln.right, None )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == False )
	assert( ln.right_edited == True )

	ln = lines[2]
	assert_strings_equal( ln.left, "line 3 here" )
	assert_strings_equal( ln.right, "edited 3c" )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == False )
	assert( ln.right_edited == True )

	assert_lines_lists_equal( old_static_lines, staticdiffmodel.get_lines() )
def added_at_beginning():

	file1 = [
		"line 3 here\n",
		"line 4 here\n",
	]

	diff = [
		"--- test/file1.txt	2009-03-28 15:33:40.000000000 +0000\n",
		"+++ test/file2.txt	2009-03-28 15:33:45.000000000 +0000\n",
		"@@ -1,2 +1,4 @@\n",
		"+line 1 here\n",
		"+line 2 here\n",
		" line 3 here\n",
		" line 4 here\n",
	]

	unifieddiffparser = UnifiedDiffParser( file1, diff )
	diffmodel = DiffModel( unifieddiffparser )

	lines = diffmodel.get_lines()

	assert( lines[0].left is None )
	assert_strings_equal( lines[0].right, "line 1 here" )
	assert( lines[0].status == difflinetypes.ADD )

	assert( lines[1].left is None )
	assert_strings_equal( lines[1].right, "line 2 here" )
	assert( lines[1].status == difflinetypes.ADD )

	assert_strings_equal( lines[2].left, "line 3 here" )
	assert_strings_equal( lines[2].right, "line 3 here" )
	assert( lines[2].status == difflinetypes.IDENTICAL )

	assert_strings_equal( lines[3].left, "line 4 here" )
	assert_strings_equal( lines[3].right, "line 4 here" )
	assert( lines[3].status == difflinetypes.IDENTICAL )
def add_lines_containing():
	"""The lines containing an add are calculated correctly."""

	staticdiffmodel = _make_static_diffmodel()
	editable = EditableDiffModel( staticdiffmodel )

	editable.add_lines( 3, directions.LEFT, ["new line 3a", "new line 3b"] )

	# Get some lines containing the add
	lines = editable.get_lines( 1, 6 )
	assert( len( lines ) == 5 )

	ln = lines[0]
	assert_strings_equal( ln.left, "line 2 here" )
	assert_strings_equal( ln.right, "line 2 here" )
	assert( ln.status == difflinetypes.IDENTICAL )
	assert( ln.left_edited == False )
	assert( ln.right_edited == False )
	assert( ln == editable.get_line( 1 ) ) # Sanity for get_line

	ln = lines[1]
	assert_strings_equal( ln.left, "line 3 here" )
	assert_strings_equal( ln.right, "line 3 here" )
	assert( ln.status == difflinetypes.IDENTICAL )
	assert( ln.left_edited == False )
	assert( ln.right_edited == False )
	assert( ln == editable.get_line( 2 ) ) # Sanity for get_line

	ln = lines[2]
	assert_strings_equal( ln.left, "new line 3a" )
	assert_strings_equal( ln.right, None )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == True )
	assert( ln.right_edited == False )
	assert( ln == editable.get_line( 3 ) ) # Sanity for get_line

	ln = lines[3]
	assert_strings_equal( ln.left, "new line 3b" )
	assert_strings_equal( ln.right, None )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == True )
	assert( ln.right_edited == False )
	assert( ln == editable.get_line( 4 ) ) # Sanity for get_line

	ln = lines[4]
	assert_strings_equal( ln.left, "line 4 here" )
	assert_strings_equal( ln.right, "line 4 here" )
	assert( ln.status == difflinetypes.IDENTICAL )
	assert( ln.left_edited == False )
	assert( ln.right_edited == False )
	assert( ln == editable.get_line( 5 ) ) # Sanity for get_line
def removed_in_middle():

	file1 = [
		"line 1 here\n",
		"line 2 here\n",
		"line 3 here\n",
		"line 4 here\n",
		"line 5 here\n",
		"line 6 here\n",
		"line 7 here\n",
		"line 8 here\n",
		"line 9 here\n",
		"line 10 here\n",
		"line 11 here\n",
		"line 12 here\n",
		"line 13 here\n",
		"line 14 here\n",
		"line 15 here\n",
		"line 16 here\n",
	]

	diff = [
		"--- test/file1.txt	2009-03-28 20:29:28.000000000 +0000\n",
		"+++ test/file2.txt	2009-03-28 20:29:37.000000000 +0000\n",
		"@@ -1,5 +1,4 @@\n",
		" line 1 here\n",
		"-line 2 here\n",
		" line 3 here\n",
		" line 4 here\n",
		" line 5 here\n",
		"@@ -12,5 +11,4 @@\n",
		" line 12 here\n",
		" line 13 here\n",
		" line 14 here\n",
		"-line 15 here\n",
		" line 16 here\n",
	]

	unifieddiffparser = UnifiedDiffParser( file1, diff )
	diffmodel = DiffModel( unifieddiffparser )

	lines = diffmodel.get_lines()

	assert_strings_equal( lines[0].left,  "line 1 here" )
	assert_strings_equal( lines[0].right, "line 1 here" )
	assert( lines[0].status == difflinetypes.IDENTICAL )

	assert_strings_equal( lines[1].left, "line 2 here" )
	assert( lines[1].right is None )
	assert( lines[1].status == difflinetypes.REMOVE )

	for i in range( 3, 15 ):
		assert_strings_equal( lines[i-1].left,  "line %d here" % i )
		assert_strings_equal( lines[i-1].right, "line %d here" % i )
		assert( lines[i-1].status == difflinetypes.IDENTICAL )

	assert_strings_equal( lines[14].left, "line 15 here" )
	assert( lines[14].right is None )
	assert( lines[14].status == difflinetypes.REMOVE )

	assert_strings_equal( lines[15].left, "line 16 here" )
	assert_strings_equal( lines[15].right, "line 16 here" )
	assert( lines[15].status == difflinetypes.IDENTICAL )
def add_lines_overlapping_left():
	"""If an add overlaps the region we are asking for on the left,
	we still calculate the right answer."""

	staticdiffmodel = _make_static_diffmodel()
	editable = EditableDiffModel( staticdiffmodel )

	editable.add_lines( 3, directions.RIGHT,
		[
		"new line 3a",
		"new line 3b",
		"new line 3c",
		"new line 3d",
		] )

	# Get some lines containing the add
	lines = editable.get_lines( 5, 8 )
	assert( len( lines ) == 3 )

	ln = lines[0]
	assert_strings_equal( ln.left, None )
	assert_strings_equal( ln.right, "new line 3c" )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == False )
	assert( ln.right_edited == True )
	assert( ln == editable.get_line( 5 ) ) # Sanity for get_line

	ln = editable.get_line( 6 )
	assert_strings_equal( ln.left, None )
	assert_strings_equal( ln.right, "new line 3d" )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == False )
	assert( ln.right_edited == True )
	assert( ln == lines[1] ) # Sanity - get_lines gives same answer as get_line

	ln = lines[2]
	assert_strings_equal( ln.left, "line 4 here" )
	assert_strings_equal( ln.right, "line 4 here" )
	assert( ln.status == difflinetypes.IDENTICAL )
	assert( ln.left_edited == False )
	assert( ln.right_edited == False )
	assert( ln == editable.get_line( 7 ) ) # Sanity for get_line
def changed_added_removed():

	file1 = [
		"line 1 here\n",
		"line 2 here\n",
		"line 3 here\n",
		"line 4 here\n",
		"line 5 here\n",
		"line 7 here\n",
		"line 8 here\n",
		"line 9 here\n",
		"line 10 here\n",
	]

	diff = [
		"--- test/file1.txt	2009-03-28 20:37:54.000000000 +0000\n",
		"+++ test/file2.txt	2009-03-28 20:37:47.000000000 +0000\n",
		"@@ -1,9 +1,8 @@\n",
		" line 1 here\n",
		"-line 2 here\n",
		"-line 3 here\n",
		"+line 2 here different\n",
		" line 4 here\n",
		" line 5 here\n",
		"+line 6 here\n",
		" line 7 here\n",
		" line 8 here\n",
		"-line 9 here\n",
		" line 10 here\n",
	]

	unifieddiffparser = UnifiedDiffParser( file1, diff )
	diffmodel = DiffModel( unifieddiffparser )

	lines = diffmodel.get_lines()

	assert_strings_equal( lines[0].left, "line 1 here" )
	assert_strings_equal( lines[0].right, "line 1 here" )
	assert( lines[0].status == difflinetypes.IDENTICAL )

	assert_strings_equal( lines[1].left, "line 2 here" )
	assert_strings_equal( lines[1].right, "line 2 here different" )
	assert( lines[1].status == difflinetypes.DIFFERENT )

	assert_strings_equal( lines[2].left, "line 3 here" )
	assert( lines[2].right is None )
	assert( lines[2].status == difflinetypes.REMOVE )

	assert_strings_equal( lines[3].left, "line 4 here" )
	assert_strings_equal( lines[3].right, "line 4 here" )
	assert( lines[3].status == difflinetypes.IDENTICAL )

	assert_strings_equal( lines[4].left, "line 5 here" )
	assert_strings_equal( lines[4].right, "line 5 here" )
	assert( lines[4].status == difflinetypes.IDENTICAL )

	assert( lines[5].left is None )
	assert_strings_equal( lines[5].right, "line 6 here" )
	assert( lines[5].status == difflinetypes.ADD )

	assert_strings_equal( lines[6].left, "line 7 here" )
	assert_strings_equal( lines[6].right, "line 7 here" )
	assert( lines[6].status == difflinetypes.IDENTICAL )

	assert_strings_equal( lines[7].left, "line 8 here" )
	assert_strings_equal( lines[7].right, "line 8 here" )
	assert( lines[7].status == difflinetypes.IDENTICAL )

	assert_strings_equal( lines[8].left, "line 9 here" )
	assert( lines[8].right is None )
	assert( lines[8].status == difflinetypes.REMOVE )

	assert_strings_equal( lines[9].left, "line 10 here" )
	assert_strings_equal( lines[9].right, "line 10 here" )
	assert( lines[9].status == difflinetypes.IDENTICAL )
def edit_spans_before_and_after():
	staticdiffmodel = _make_static_diffmodel()

	editable = EditableDiffModel( staticdiffmodel )

	# Change all 10 lines
	editable.edit_lines( 0, 9, directions.RIGHT,
		( "edited 1", "edited 2", "edited 3", "edited 4", "edited 5",
		  "edited 6", "edited 7", "edited 8", "edited 9", "edited 10" ) )

	# Just ask for lines 7, 8 and 9
	lines = editable.get_lines( 6, 10 )
	assert( len( lines ) == 4 )

	assert_strings_equal( lines[0].left, "line 7 here" )
	assert_strings_equal( lines[0].right, "edited 7" )
	assert( lines[0].status == difflinetypes.DIFFERENT )
	assert( lines[0].left_edited == False )
	assert( lines[0].right_edited == True )

	assert_strings_equal( lines[1].left, "line 8 here" )
	assert_strings_equal( lines[1].right, "edited 8" )
	assert( lines[1].status == difflinetypes.DIFFERENT )
	assert( lines[1].left_edited == False )
	assert( lines[1].right_edited == True )

	assert_strings_equal( lines[2].left, "line 9 here" )
	assert_strings_equal( lines[2].right, "edited 9" )
	assert( lines[2].status == difflinetypes.DIFFERENT )
	assert( lines[2].left_edited == False )
	assert( lines[2].right_edited == True )

	ln = editable.get_line( 0 )
	assert_strings_equal( ln.left, "line 1 here" )
	assert_strings_equal( ln.right, "edited 1" )
	assert( ln.status == difflinetypes.DIFFERENT )
	assert( ln.left_edited == False )
	assert( ln.right_edited == True )
def diff_then_same():
	file1 = [
		"line 1 here\n",
		"line 2 here\n",
		"line 3 here\n",
		"line 4 here\n",
	]

	diff = [
		"--- test/file1.txt	2009-03-27 21:06:15.000000000 +0000\n",
		"+++ test/file2.txt	2009-03-27 21:11:54.000000000 +0000\n",
		"@@ -1,4 +1,4 @@\n",
		"-line 1 here\n",
		"-line 2 here\n",
		"+line 1 here different\n",
		"+line 2 here different\n",
		" line 3 here\n",
		" line 4 here\n",
	]

	unifieddiffparser = UnifiedDiffParser( file1, diff )
	diffmodel = DiffModel( unifieddiffparser )

	lines = diffmodel.get_lines()

	assert_strings_equal( lines[0].left,  "line 1 here" )
	assert_strings_equal( lines[0].right, "line 1 here different" )
	assert( lines[0].status == difflinetypes.DIFFERENT )

	assert_strings_equal( lines[1].left,  "line 2 here" )
	assert_strings_equal( lines[1].right, "line 2 here different" )
	assert( lines[1].status == difflinetypes.DIFFERENT )

	assert_strings_equal( lines[2].left,  "line 3 here" )
	assert_strings_equal( lines[2].right, "line 3 here" )
	assert( lines[2].status == difflinetypes.IDENTICAL )

	assert_strings_equal( lines[3].left,  "line 4 here" )
	assert_strings_equal( lines[3].right, "line 4 here" )
	assert( lines[3].status == difflinetypes.IDENTICAL )
def edit_doesnt_change_line():
	staticdiffmodel = _make_static_diffmodel()
	old_static_lines = list( ln.clone() for ln in staticdiffmodel.get_lines() )

	editable = EditableDiffModel( staticdiffmodel )

	# Make a change that actually doesn't change some lines
	editable.edit_lines( 0, 2, directions.LEFT,
		( "line 1 here", "edited 2", "line 3 here" ) )

	# Ask for lines 1 to 3
	lines = editable.get_lines( 0, 3 )
	assert( len( lines ) == 3 )

	assert_strings_equal( lines[0].left, "line 1 here" )
	assert_strings_equal( lines[0].right, "line 1 here" )
	assert( lines[0].status == difflinetypes.IDENTICAL )
	assert( lines[0].left_edited == True ) # Because this is part of a real
	                                       # change, we do mark it as changed.
	                                       # This may be fixed in future
	assert( lines[0].right_edited == False )

	assert_strings_equal( lines[1].left, "edited 2" )
	assert_strings_equal( lines[1].right, "line 2 here" )
	assert( lines[1].status == difflinetypes.DIFFERENT )
	assert( lines[1].left_edited == True )
	assert( lines[1].right_edited == False )

	assert_strings_equal( lines[2].left, "line 3 here" )
	assert_strings_equal( lines[2].right, "line 3 here" )
	assert( lines[2].status == difflinetypes.IDENTICAL )
	assert( lines[2].left_edited == True ) # Because this is part of a real
	                                       # change, we do mark it as changed.
	                                       # This may be fixed in future
	assert( lines[2].right_edited == False )

	assert_lines_lists_equal( old_static_lines, staticdiffmodel.get_lines() )