2020-08-23 13:42:15 +03:00
|
|
|
package json_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"testing"
|
|
|
|
|
2023-11-20 04:06:36 +03:00
|
|
|
"github.com/stretchr/testify/require"
|
2023-04-02 22:49:45 +03:00
|
|
|
|
2020-08-23 13:42:15 +03:00
|
|
|
"github.com/neilotoole/sq/drivers/json"
|
2023-11-20 04:06:36 +03:00
|
|
|
"github.com/neilotoole/sq/libsq/core/lg"
|
2024-01-15 04:45:34 +03:00
|
|
|
"github.com/neilotoole/sq/libsq/core/lg/lgt"
|
2020-08-23 13:42:15 +03:00
|
|
|
"github.com/neilotoole/sq/libsq/source"
|
2023-11-21 00:42:38 +03:00
|
|
|
"github.com/neilotoole/sq/libsq/source/drivertype"
|
2024-01-15 04:45:34 +03:00
|
|
|
"github.com/neilotoole/sq/testh/tu"
|
2020-08-23 13:42:15 +03:00
|
|
|
)
|
|
|
|
|
2023-04-22 06:36:32 +03:00
|
|
|
func TestDriverDetectorFuncs(t *testing.T) {
|
2023-05-03 15:36:10 +03:00
|
|
|
const sampleSize = 1000
|
|
|
|
|
2023-11-21 00:42:38 +03:00
|
|
|
detectFns := map[drivertype.Type]source.DriverDetectFunc{ //nolint:exhaustive
|
2023-05-03 15:36:10 +03:00
|
|
|
json.TypeJSON: json.DetectJSON(sampleSize),
|
|
|
|
json.TypeJSONA: json.DetectJSONA(sampleSize),
|
|
|
|
json.TypeJSONL: json.DetectJSONL(sampleSize),
|
2020-08-23 13:42:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
testCases := []struct {
|
2023-11-21 00:42:38 +03:00
|
|
|
fn drivertype.Type
|
2020-10-20 18:05:43 +03:00
|
|
|
fname string
|
2023-11-21 00:42:38 +03:00
|
|
|
// Note that the zero value is drivertype.None.
|
|
|
|
want drivertype.Type
|
2020-10-20 18:05:43 +03:00
|
|
|
// If wantScore is zero, it's not inspected. If non-zero,
|
|
|
|
// gotScore is tested against wantScore
|
|
|
|
wantScore float32
|
|
|
|
wantErr bool
|
2020-08-23 13:42:15 +03:00
|
|
|
}{
|
2020-10-20 18:05:43 +03:00
|
|
|
// JSON detector
|
|
|
|
{fn: json.TypeJSON, fname: "actor.json", want: json.TypeJSON},
|
|
|
|
{fn: json.TypeJSON, fname: "film_actor.json", want: json.TypeJSON},
|
|
|
|
{fn: json.TypeJSON, fname: "payment.json", want: json.TypeJSON},
|
|
|
|
{fn: json.TypeJSON, fname: "address_1_object.json", want: json.TypeJSON},
|
|
|
|
{fn: json.TypeJSON, fname: "1_record_on_1_line.jsonl", want: json.TypeJSON, wantScore: 0.9},
|
|
|
|
{fn: json.TypeJSON, fname: "1_record_over_n_lines.json", want: json.TypeJSON, wantScore: 1.0},
|
|
|
|
{fn: json.TypeJSON, fname: "jsona_bad_1.jsona"},
|
|
|
|
{fn: json.TypeJSON, fname: "jsona_good_1.jsona"},
|
|
|
|
{fn: json.TypeJSON, fname: "film_actor.jsona"},
|
|
|
|
{fn: json.TypeJSON, fname: "payment.jsona"},
|
|
|
|
{fn: json.TypeJSON, fname: "actor.jsona"},
|
|
|
|
{fn: json.TypeJSON, fname: "actor.jsonl"},
|
|
|
|
{fn: json.TypeJSON, fname: "film_actor.jsona"},
|
|
|
|
{fn: json.TypeJSON, fname: "film_actor.jsonl"},
|
|
|
|
{fn: json.TypeJSON, fname: "payment.jsona"},
|
|
|
|
{fn: json.TypeJSON, fname: "payment.jsonl"},
|
|
|
|
{fn: json.TypeJSON, fname: "jsonl_good_1.jsonl"},
|
|
|
|
{fn: json.TypeJSON, fname: "jsonl_bad_1.jsonl"},
|
|
|
|
|
|
|
|
// JSONA detector
|
|
|
|
{fn: json.TypeJSONA, fname: "actor.jsona", want: json.TypeJSONA},
|
|
|
|
{fn: json.TypeJSONA, fname: "1_record_on_1_line.jsonl"},
|
|
|
|
{fn: json.TypeJSONA, fname: "1_record_over_n_lines.json"},
|
|
|
|
{fn: json.TypeJSONA, fname: "jsona_bad_1.jsona"},
|
|
|
|
{fn: json.TypeJSONA, fname: "jsona_good_1.jsona", want: json.TypeJSONA},
|
|
|
|
{fn: json.TypeJSONA, fname: "film_actor.jsona", want: json.TypeJSONA},
|
|
|
|
{fn: json.TypeJSONA, fname: "payment.jsona", want: json.TypeJSONA},
|
|
|
|
{fn: json.TypeJSONA, fname: "actor.json"},
|
|
|
|
{fn: json.TypeJSONA, fname: "actor.jsonl"},
|
|
|
|
{fn: json.TypeJSONA, fname: "film_actor.json"},
|
|
|
|
{fn: json.TypeJSONA, fname: "film_actor.jsonl"},
|
|
|
|
{fn: json.TypeJSONA, fname: "payment.json"},
|
|
|
|
{fn: json.TypeJSONA, fname: "payment.jsonl"},
|
|
|
|
{fn: json.TypeJSONA, fname: "jsonl_good_1.jsonl"},
|
|
|
|
{fn: json.TypeJSONA, fname: "jsonl_bad_1.jsonl"},
|
|
|
|
// JSONL detector
|
|
|
|
{fn: json.TypeJSONL, fname: "actor.jsonl", want: json.TypeJSONL},
|
|
|
|
{fn: json.TypeJSONL, fname: "jsonl_good_1.jsonl", want: json.TypeJSONL},
|
|
|
|
{fn: json.TypeJSONL, fname: "1_record_on_1_line.jsonl", want: json.TypeJSONL},
|
|
|
|
{fn: json.TypeJSONL, fname: "1_record_over_n_lines.json"},
|
|
|
|
{fn: json.TypeJSONL, fname: "jsonl_bad_1.jsonl"},
|
|
|
|
{fn: json.TypeJSONL, fname: "actor.jsona"},
|
|
|
|
{fn: json.TypeJSONL, fname: "actor.json"},
|
|
|
|
{fn: json.TypeJSONL, fname: "film_actor.jsonl", want: json.TypeJSONL},
|
|
|
|
{fn: json.TypeJSONL, fname: "film_actor.jsona"},
|
|
|
|
{fn: json.TypeJSONL, fname: "film_actor.json"},
|
|
|
|
{fn: json.TypeJSONL, fname: "payment.jsonl", want: json.TypeJSONL},
|
|
|
|
{fn: json.TypeJSONL, fname: "payment.jsona"},
|
|
|
|
{fn: json.TypeJSONL, fname: "payment.json"},
|
2020-08-23 13:42:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range testCases {
|
|
|
|
tc := tc
|
|
|
|
|
2024-01-15 04:45:34 +03:00
|
|
|
t.Run(tu.Name(tc.fn, tc.fname), func(t *testing.T) {
|
|
|
|
openFn := func(ctx context.Context) (io.ReadCloser, error) { return os.Open(filepath.Join("testdata", tc.fname)) }
|
2020-08-23 13:42:15 +03:00
|
|
|
detectFn := detectFns[tc.fn]
|
|
|
|
|
2024-01-15 04:45:34 +03:00
|
|
|
ctx := lg.NewContext(context.Background(), lgt.New(t))
|
2023-04-02 22:49:45 +03:00
|
|
|
|
|
|
|
gotType, gotScore, gotErr := detectFn(ctx, openFn)
|
2020-08-23 13:42:15 +03:00
|
|
|
if tc.wantErr {
|
|
|
|
require.Error(t, gotErr)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
require.NoError(t, gotErr)
|
|
|
|
require.Equal(t, tc.want, gotType)
|
2023-11-21 00:42:38 +03:00
|
|
|
if tc.want == drivertype.None {
|
2020-08-23 13:42:15 +03:00
|
|
|
require.Equal(t, float32(0), gotScore)
|
2020-10-20 18:05:43 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if tc.wantScore != 0 {
|
|
|
|
require.Equal(t, tc.wantScore, gotScore)
|
2020-08-23 13:42:15 +03:00
|
|
|
} else {
|
|
|
|
require.Equal(t, float32(1.0), gotScore)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|