Skip to content

Commit ed65847

Browse files
authored
Merge pull request #219 from Mystigan/master
Add tests for Levenshtein distance and naive search algorithms
2 parents 410db77 + baca44f commit ed65847

File tree

5 files changed

+108
-53
lines changed

5 files changed

+108
-53
lines changed

.github/workflows/golangci-lint.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ jobs:
2929
- run: golangci-lint run --no-config other || true
3030
- run: golangci-lint run --no-config searches || true
3131
- run: golangci-lint run --no-config sorts
32-
- run: golangci-lint run --no-config strings
32+
# - run: golangci-lint run --no-config strings/...
3333
- run: golangci-lint run --no-config "strings/multiple string matching" || true
3434
# - run: golangci-lint run --no-config "strings/single string matching" || true
35+
- run: golangci-lint run --no-config strings/levenshteindistance
36+
- run: golangci-lint run --no-config strings/naivesearch

strings/levenshteinDistance.go renamed to strings/levenshteindistance/levenshteinDistance.go

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,11 @@ Parameters: two strings to compare and weights of insertion, substitution and de
44
Output: distance between both strings
55
*/
66

7-
package main
8-
9-
import (
10-
"fmt"
11-
)
7+
package levenshteindistance
128

139
func levenshteinDistance(str1, str2 string, icost, scost, dcost int) int {
1410
row1 := make([]int, len(str2)+1)
1511
row2 := make([]int, len(str2)+1)
16-
var tmp []int
1712

1813
for i := 1; i <= len(str2); i++ {
1914
row1[i] = i * icost
@@ -39,35 +34,8 @@ func levenshteinDistance(str1, str2 string, icost, scost, dcost int) int {
3934
}
4035
}
4136
}
42-
43-
tmp = row1
44-
row1 = row2
45-
row2 = tmp
37+
row1, row2 = row2, row1
4638
}
4739

4840
return row1[len(row1)-1]
4941
}
50-
51-
func min(str1, str2 int) int {
52-
if str1 < str2 {
53-
return str1
54-
}
55-
return str2
56-
}
57-
58-
func main() {
59-
str1 := "stingy"
60-
str2 := "ring"
61-
62-
// Using weight 1 for insertion, substitution and deletion
63-
strDistance1 := levenshteinDistance(str1, str2, 1, 1, 1)
64-
fmt.Printf("Distance between \"%s\" and \"%s\" is: %d.\n", str1, str2, strDistance1)
65-
// Output: Distance between "stingy" and "ring" is: 3.
66-
67-
// Using weight 1 for insertion/substitution and weight 3 for deletion
68-
strDistance2 := levenshteinDistance(str1, str2, 1, 1, 3)
69-
fmt.Printf("Distance between \"%s\" and \"%s\" is: %d.\n", str1, str2, strDistance2)
70-
// Output: Distance between "stingy" and "ring" is: 7.
71-
72-
return
73-
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package levenshteindistance
2+
3+
import "testing"
4+
5+
var testCases = []struct {
6+
name string
7+
string1 string
8+
string2 string
9+
insertionCost int
10+
substitutionCost int
11+
deletionCost int
12+
expected int
13+
}{
14+
{
15+
"strings with equal operation weights.",
16+
"stingy",
17+
"ring",
18+
1,
19+
1,
20+
1,
21+
3,
22+
},
23+
{
24+
"strings with different operation weights.",
25+
"stingy",
26+
"ring",
27+
1,
28+
1,
29+
3,
30+
7,
31+
},
32+
{
33+
"strings with different operation weights.",
34+
"kitten",
35+
"sitting",
36+
1,
37+
1,
38+
1,
39+
3,
40+
},
41+
}
42+
43+
func TestLevenshteinDistance(t *testing.T) {
44+
for _, tc := range testCases {
45+
t.Run(tc.name, func(t *testing.T) {
46+
actual := levenshteinDistance(tc.string1, tc.string2, tc.insertionCost, tc.substitutionCost, tc.deletionCost)
47+
if actual != tc.expected {
48+
t.Errorf("Expected Levenshtein distance between strings: '%s' and '%s' is %v, but got: %v", tc.string1, tc.string2, tc.expected, actual)
49+
}
50+
})
51+
}
52+
}

strings/naiveStringSearch.go renamed to strings/naivesearch/naiveStringSearch.go

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,11 @@ Time Complexity : O(n*m)
88
m = length of pattern
99
*/
1010

11-
package main
12-
13-
import (
14-
"fmt"
15-
)
11+
package naivesearch
1612

1713
func naivePatternSearch(text string, pattern string) []int {
1814
var positions []int
19-
for i := 0; i < len(text)-len(pattern); i++ {
15+
for i := 0; i <= len(text)-len(pattern); i++ {
2016
var match bool = true
2117
for j := 0; j < len(pattern); j++ {
2218
if text[i+j] != pattern[j] {
@@ -31,15 +27,3 @@ func naivePatternSearch(text string, pattern string) []int {
3127
}
3228
return positions
3329
}
34-
35-
func main() {
36-
text := "ABAAABCDBBABCDDEBCABC"
37-
pattern := "ABC"
38-
var positions []int = naivePatternSearch(text, pattern)
39-
if len(positions) == 0 {
40-
fmt.Printf("Pattern not found in given text!")
41-
} else {
42-
fmt.Printf("Pattern found in following position:\n")
43-
fmt.Printf("%v", positions)
44-
}
45-
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package naivesearch
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
)
7+
8+
var testCases = []struct {
9+
name string
10+
input string
11+
pattern string
12+
expected []int
13+
}{
14+
{
15+
"string with multiple pattern matches",
16+
"ABAAABCDBBABCDDEBCABC",
17+
"ABC",
18+
[]int{4, 10, 18},
19+
},
20+
{
21+
"string with single pattern match",
22+
"ABCDEFGHIJKLMN",
23+
"CDE",
24+
[]int{2},
25+
},
26+
{
27+
"string with no pattern match",
28+
"ABCDEFGHIJKLMN",
29+
"XYZ",
30+
[]int(nil),
31+
},
32+
{
33+
"empty string",
34+
"",
35+
"XYZ",
36+
[]int(nil),
37+
},
38+
}
39+
40+
func TestNaivePatternSearch(t *testing.T) {
41+
for _, tc := range testCases {
42+
t.Run(tc.name, func(t *testing.T) {
43+
actual := naivePatternSearch(tc.input, tc.pattern)
44+
if !reflect.DeepEqual(actual, tc.expected) {
45+
t.Errorf("Expected matches for pattern '%s' for string '%s' are: %v, but actual matches are: %v", tc.pattern, tc.input, tc.expected, actual)
46+
}
47+
})
48+
}
49+
}

0 commit comments

Comments
 (0)