1// Copyright 2017 Google LLC
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 bigquery
16
17import (
18	"testing"
19
20	"cloud.google.com/go/internal/pretty"
21	"cloud.google.com/go/internal/testutil"
22)
23
24func TestExternalDataConfig(t *testing.T) {
25	// Round-trip of ExternalDataConfig to underlying representation.
26	for i, want := range []*ExternalDataConfig{
27		{
28			SourceFormat:        CSV,
29			SourceURIs:          []string{"uri"},
30			Schema:              Schema{{Name: "n", Type: IntegerFieldType}},
31			AutoDetect:          true,
32			Compression:         Gzip,
33			IgnoreUnknownValues: true,
34			MaxBadRecords:       17,
35			Options: &CSVOptions{
36				AllowJaggedRows:     true,
37				AllowQuotedNewlines: true,
38				Encoding:            UTF_8,
39				FieldDelimiter:      "f",
40				Quote:               "q",
41				SkipLeadingRows:     3,
42			},
43		},
44		{
45			SourceFormat: GoogleSheets,
46			Options:      &GoogleSheetsOptions{SkipLeadingRows: 4},
47		},
48		{
49			SourceFormat: Bigtable,
50			Options: &BigtableOptions{
51				IgnoreUnspecifiedColumnFamilies: true,
52				ReadRowkeyAsString:              true,
53				ColumnFamilies: []*BigtableColumnFamily{
54					{
55						FamilyID:       "f1",
56						Encoding:       "TEXT",
57						OnlyReadLatest: true,
58						Type:           "FLOAT",
59						Columns: []*BigtableColumn{
60							{
61								Qualifier:      "valid-utf-8",
62								FieldName:      "fn",
63								OnlyReadLatest: true,
64								Encoding:       "BINARY",
65								Type:           "STRING",
66							},
67						},
68					},
69				},
70			},
71		},
72	} {
73		q := want.toBQ()
74		got, err := bqToExternalDataConfig(&q)
75		if err != nil {
76			t.Fatal(err)
77		}
78		if diff := testutil.Diff(got, want); diff != "" {
79			t.Errorf("#%d: got=-, want=+:\n%s", i, diff)
80		}
81	}
82}
83
84func TestQuote(t *testing.T) {
85	ptr := func(s string) *string { return &s }
86
87	for _, test := range []struct {
88		quote string
89		force bool
90		want  *string
91	}{
92		{"", false, nil},
93		{"", true, ptr("")},
94		{"-", false, ptr("-")},
95		{"-", true, ptr("")},
96	} {
97		o := CSVOptions{
98			Quote:          test.quote,
99			ForceZeroQuote: test.force,
100		}
101		got := o.quote()
102		if (got == nil) != (test.want == nil) {
103			t.Errorf("%+v\ngot %v\nwant %v", test, pretty.Value(got), pretty.Value(test.want))
104		}
105		if got != nil && test.want != nil && *got != *test.want {
106			t.Errorf("%+v: got %q, want %q", test, *got, *test.want)
107		}
108	}
109}
110
111func TestQualifier(t *testing.T) {
112	b := BigtableColumn{Qualifier: "a"}
113	q := b.toBQ()
114	if q.QualifierString != b.Qualifier || q.QualifierEncoded != "" {
115		t.Errorf("got (%q, %q), want (%q, %q)",
116			q.QualifierString, q.QualifierEncoded, b.Qualifier, "")
117	}
118	b2, err := bqToBigtableColumn(q)
119	if err != nil {
120		t.Fatal(err)
121	}
122	if got, want := b2.Qualifier, b.Qualifier; got != want {
123		t.Errorf("got %q, want %q", got, want)
124	}
125
126	const (
127		invalidUTF8    = "\xDF\xFF"
128		invalidEncoded = "3/8"
129	)
130	b = BigtableColumn{Qualifier: invalidUTF8}
131	q = b.toBQ()
132	if q.QualifierString != "" || q.QualifierEncoded != invalidEncoded {
133		t.Errorf("got (%q, %q), want (%q, %q)",
134			q.QualifierString, "", b.Qualifier, invalidEncoded)
135	}
136	b2, err = bqToBigtableColumn(q)
137	if err != nil {
138		t.Fatal(err)
139	}
140	if got, want := b2.Qualifier, b.Qualifier; got != want {
141		t.Errorf("got %q, want %q", got, want)
142	}
143}
144