1// Copyright 2012 Aryan Naraghi (aryan.naraghi@gmail.com)
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package difflib
16
17import (
18	"reflect"
19	"strings"
20	"testing"
21)
22
23var lcsTests = []struct {
24	seq1 string
25	seq2 string
26	lcs  int
27}{
28	{"", "", 0},
29	{"abc", "abc", 3},
30	{"mzjawxu", "xmjyauz", 4},
31	{"human", "chimpanzee", 4},
32	{"Hello, world!", "Hello, world!", 13},
33	{"Hello, world!", "H     e    l  l o ,   w  o r l  d   !", 13},
34}
35
36func TestLongestCommonSubsequenceMatrix(t *testing.T) {
37	for i, test := range lcsTests {
38		seq1 := strings.Split(test.seq1, "")
39		seq2 := strings.Split(test.seq2, "")
40		matrix := longestCommonSubsequenceMatrix(seq1, seq2)
41		lcs := matrix[len(matrix)-1][len(matrix[0])-1] // Grabs the lower, right value.
42		if lcs != test.lcs {
43			t.Errorf("%d. longestCommonSubsequence(%v, %v)[last][last] => %d, expected %d",
44				i, seq1, seq2, lcs, test.lcs)
45		}
46	}
47}
48
49var numEqualStartAndEndElementsTests = []struct {
50	seq1  string
51	seq2  string
52	start int
53	end   int
54}{
55	{"", "", 0, 0},
56	{"abc", "", 0, 0},
57	{"", "abc", 0, 0},
58	{"abc", "abc", 3, 0},
59	{"abhelloc", "abbyec", 2, 1},
60	{"abchello", "abcbye", 3, 0},
61	{"helloabc", "byeabc", 0, 3},
62}
63
64func TestNumEqualStartAndEndElements(t *testing.T) {
65	for i, test := range numEqualStartAndEndElementsTests {
66		seq1 := strings.Split(test.seq1, "")
67		seq2 := strings.Split(test.seq2, "")
68		start, end := numEqualStartAndEndElements(seq1, seq2)
69		if start != test.start || end != test.end {
70			t.Errorf("%d. numEqualStartAndEndElements(%v, %v) => (%d, %d), expected (%d, %d)",
71				i, seq1, seq2, start, end, test.start, test.end)
72		}
73	}
74}
75
76var diffTests = []struct {
77	Seq1     string
78	Seq2     string
79	Diff     []DiffRecord
80	HtmlDiff string
81}{
82	{
83		"",
84		"",
85		[]DiffRecord{
86			{"", Common},
87		},
88		`<tr><td class="line-num">1</td><td><pre></pre></td><td><pre></pre></td><td class="line-num">1</td></tr>
89`,
90	},
91
92	{
93		"same",
94		"same",
95		[]DiffRecord{
96			{"same", Common},
97		},
98		`<tr><td class="line-num">1</td><td><pre>same</pre></td><td><pre>same</pre></td><td class="line-num">1</td></tr>
99`,
100	},
101
102	{
103		`one
104two
105three
106`,
107		`one
108two
109three
110`,
111		[]DiffRecord{
112			{"one", Common},
113			{"two", Common},
114			{"three", Common},
115			{"", Common},
116		},
117		`<tr><td class="line-num">1</td><td><pre>one</pre></td><td><pre>one</pre></td><td class="line-num">1</td></tr>
118<tr><td class="line-num">2</td><td><pre>two</pre></td><td><pre>two</pre></td><td class="line-num">2</td></tr>
119<tr><td class="line-num">3</td><td><pre>three</pre></td><td><pre>three</pre></td><td class="line-num">3</td></tr>
120<tr><td class="line-num">4</td><td><pre></pre></td><td><pre></pre></td><td class="line-num">4</td></tr>
121`,
122	},
123
124	{
125		`one
126two
127three
128`,
129		`one
130five
131three
132`,
133		[]DiffRecord{
134			{"one", Common},
135			{"two", LeftOnly},
136			{"five", RightOnly},
137			{"three", Common},
138			{"", Common},
139		},
140		`<tr><td class="line-num">1</td><td><pre>one</pre></td><td><pre>one</pre></td><td class="line-num">1</td></tr>
141<tr><td class="line-num">2</td><td class="deleted"><pre>two</pre></td><td></td><td class="line-num"></td></tr>
142<tr><td class="line-num"></td><td></td><td class="added"><pre>five</pre></td><td class="line-num">2</td></tr>
143<tr><td class="line-num">3</td><td><pre>three</pre></td><td><pre>three</pre></td><td class="line-num">3</td></tr>
144<tr><td class="line-num">4</td><td><pre></pre></td><td><pre></pre></td><td class="line-num">4</td></tr>
145`,
146	},
147
148	{
149		`Beethoven
150Bach
151Mozart
152Chopin
153`,
154		`Beethoven
155Bach
156Brahms
157Chopin
158Liszt
159Wagner
160`,
161
162		[]DiffRecord{
163			{"Beethoven", Common},
164			{"Bach", Common},
165			{"Mozart", LeftOnly},
166			{"Brahms", RightOnly},
167			{"Chopin", Common},
168			{"Liszt", RightOnly},
169			{"Wagner", RightOnly},
170			{"", Common},
171		},
172		`<tr><td class="line-num">1</td><td><pre>Beethoven</pre></td><td><pre>Beethoven</pre></td><td class="line-num">1</td></tr>
173<tr><td class="line-num">2</td><td><pre>Bach</pre></td><td><pre>Bach</pre></td><td class="line-num">2</td></tr>
174<tr><td class="line-num">3</td><td class="deleted"><pre>Mozart</pre></td><td></td><td class="line-num"></td></tr>
175<tr><td class="line-num"></td><td></td><td class="added"><pre>Brahms</pre></td><td class="line-num">3</td></tr>
176<tr><td class="line-num">4</td><td><pre>Chopin</pre></td><td><pre>Chopin</pre></td><td class="line-num">4</td></tr>
177<tr><td class="line-num"></td><td></td><td class="added"><pre>Liszt</pre></td><td class="line-num">5</td></tr>
178<tr><td class="line-num"></td><td></td><td class="added"><pre>Wagner</pre></td><td class="line-num">6</td></tr>
179<tr><td class="line-num">5</td><td><pre></pre></td><td><pre></pre></td><td class="line-num">7</td></tr>
180`,
181	},
182
183	{
184		`adagio
185vivace
186staccato legato
187presto
188lento
189`,
190		`adagio adagio
191staccato
192staccato legato
193staccato
194legato
195allegro
196`,
197		[]DiffRecord{
198			{"adagio", LeftOnly},
199			{"vivace", LeftOnly},
200			{"adagio adagio", RightOnly},
201			{"staccato", RightOnly},
202			{"staccato legato", Common},
203			{"presto", LeftOnly},
204			{"lento", LeftOnly},
205			{"staccato", RightOnly},
206			{"legato", RightOnly},
207			{"allegro", RightOnly},
208			{"", Common},
209		},
210		`<tr><td class="line-num">1</td><td class="deleted"><pre>adagio</pre></td><td></td><td class="line-num"></td></tr>
211<tr><td class="line-num">2</td><td class="deleted"><pre>vivace</pre></td><td></td><td class="line-num"></td></tr>
212<tr><td class="line-num"></td><td></td><td class="added"><pre>adagio adagio</pre></td><td class="line-num">1</td></tr>
213<tr><td class="line-num"></td><td></td><td class="added"><pre>staccato</pre></td><td class="line-num">2</td></tr>
214<tr><td class="line-num">3</td><td><pre>staccato legato</pre></td><td><pre>staccato legato</pre></td><td class="line-num">3</td></tr>
215<tr><td class="line-num">4</td><td class="deleted"><pre>presto</pre></td><td></td><td class="line-num"></td></tr>
216<tr><td class="line-num">5</td><td class="deleted"><pre>lento</pre></td><td></td><td class="line-num"></td></tr>
217<tr><td class="line-num"></td><td></td><td class="added"><pre>staccato</pre></td><td class="line-num">4</td></tr>
218<tr><td class="line-num"></td><td></td><td class="added"><pre>legato</pre></td><td class="line-num">5</td></tr>
219<tr><td class="line-num"></td><td></td><td class="added"><pre>allegro</pre></td><td class="line-num">6</td></tr>
220<tr><td class="line-num">6</td><td><pre></pre></td><td><pre></pre></td><td class="line-num">7</td></tr>
221`,
222	},
223}
224
225func TestDiff(t *testing.T) {
226	for i, test := range diffTests {
227		seq1 := strings.Split(test.Seq1, "\n")
228		seq2 := strings.Split(test.Seq2, "\n")
229
230		diff := Diff(seq1, seq2)
231		if !reflect.DeepEqual(diff, test.Diff) {
232			t.Errorf("%d. Diff(%v, %v) => %v, expected %v",
233				i, seq1, seq2, diff, test.Diff)
234		}
235
236		htmlDiff := HTMLDiff(seq1, seq2)
237		if htmlDiff != test.HtmlDiff {
238			t.Errorf("%d. HtmlDiff(%v, %v) => %v, expected %v",
239				i, seq1, seq2, htmlDiff, test.HtmlDiff)
240		}
241
242	}
243}
244