2020-03-12 17:52:18 +00:00
|
|
|
package externalsort
|
|
|
|
|
|
|
|
import (
|
2020-03-12 20:12:36 +00:00
|
|
|
"bufio"
|
2020-03-12 17:52:18 +00:00
|
|
|
"bytes"
|
2020-03-13 00:38:48 +00:00
|
|
|
"fmt"
|
2020-03-12 17:52:18 +00:00
|
|
|
"io/ioutil"
|
2020-03-13 00:38:48 +00:00
|
|
|
"os"
|
2020-03-12 17:52:18 +00:00
|
|
|
"path"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"gitlab.com/slon/shad-go/tools/testtool"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestMerge(t *testing.T) {
|
|
|
|
for _, tc := range []struct {
|
|
|
|
name string
|
|
|
|
in []string
|
|
|
|
out string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "simple",
|
|
|
|
in: []string{`0`, `1
|
|
|
|
1
|
|
|
|
1`},
|
|
|
|
out: `0
|
|
|
|
1
|
|
|
|
1
|
2020-03-13 19:51:17 +00:00
|
|
|
1
|
|
|
|
`,
|
2020-03-12 17:52:18 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
// Merge believes lines are read in sorted order.
|
|
|
|
name: "single-unsorted-file",
|
|
|
|
in: []string{`1
|
|
|
|
0`},
|
|
|
|
out: `1
|
2020-03-13 19:51:17 +00:00
|
|
|
0
|
|
|
|
`,
|
2020-03-12 17:52:18 +00:00
|
|
|
},
|
|
|
|
} {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
out := &bytes.Buffer{}
|
2020-03-12 20:12:36 +00:00
|
|
|
w := bufio.NewWriter(out)
|
|
|
|
lw := NewWriter(w)
|
2020-03-12 17:52:18 +00:00
|
|
|
|
|
|
|
var readers []LineReader
|
|
|
|
for _, s := range tc.in {
|
|
|
|
readers = append(readers, newStringReader(s))
|
|
|
|
}
|
|
|
|
|
2020-03-12 20:12:36 +00:00
|
|
|
err := Merge(lw, readers...)
|
2020-03-12 17:52:18 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-03-12 20:12:36 +00:00
|
|
|
require.NoError(t, w.Flush())
|
2020-03-12 17:52:18 +00:00
|
|
|
require.Equal(t, tc.out, out.String())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSort_fileNotFound(t *testing.T) {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
err := Sort(&buf, testtool.RandomName())
|
|
|
|
require.Error(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSort(t *testing.T) {
|
|
|
|
testDir := path.Join("./testdata", "sort")
|
|
|
|
|
|
|
|
readTestCase := func(dir string) (in []string, out string) {
|
|
|
|
files, err := ioutil.ReadDir(dir)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
for _, f := range files {
|
|
|
|
if strings.HasPrefix(f.Name(), "in") {
|
|
|
|
in = append(in, path.Join(dir, f.Name()))
|
|
|
|
}
|
|
|
|
if f.Name() == "out.txt" {
|
|
|
|
out = path.Join(dir, f.Name())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, d := range listDirs(t, testDir) {
|
|
|
|
testCaseDir := path.Join(testDir, d)
|
|
|
|
|
|
|
|
t.Run(d, func(t *testing.T) {
|
2020-03-13 00:38:48 +00:00
|
|
|
tmpDir, err := ioutil.TempDir("", fmt.Sprintf("sort%s-", d))
|
|
|
|
require.NoError(t, err)
|
|
|
|
defer func() { _ = os.RemoveAll(tmpDir) }()
|
|
|
|
|
2020-03-12 17:52:18 +00:00
|
|
|
in, out := readTestCase(testCaseDir)
|
2020-03-13 00:38:48 +00:00
|
|
|
in = copyFiles(t, in, tmpDir)
|
2020-03-12 17:52:18 +00:00
|
|
|
|
|
|
|
var buf bytes.Buffer
|
2020-03-12 20:12:36 +00:00
|
|
|
w := bufio.NewWriter(&buf)
|
2020-03-13 00:38:48 +00:00
|
|
|
require.NoError(t, Sort(w, in...))
|
2020-03-12 17:52:18 +00:00
|
|
|
|
|
|
|
expected, err := ioutil.ReadFile(out)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-03-12 20:12:36 +00:00
|
|
|
require.NoError(t, w.Flush())
|
2020-03-12 17:52:18 +00:00
|
|
|
require.Equal(t, string(expected), buf.String())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func listDirs(t *testing.T, dir string) []string {
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
files, err := ioutil.ReadDir(dir)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
var dirs []string
|
|
|
|
for _, f := range files {
|
|
|
|
if f.IsDir() {
|
|
|
|
dirs = append(dirs, f.Name())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return dirs
|
|
|
|
}
|
2020-03-13 00:38:48 +00:00
|
|
|
|
|
|
|
func copyFiles(t *testing.T, in []string, dir string) []string {
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
var ret []string
|
|
|
|
for _, f := range in {
|
|
|
|
ret = append(ret, copyFile(t, f, dir))
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
func copyFile(t *testing.T, f, dir string) string {
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
data, err := ioutil.ReadFile(f)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
dst := path.Join(dir, path.Base(f))
|
|
|
|
err = ioutil.WriteFile(dst, data, 0644)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
return dst
|
|
|
|
}
|