diff --git a/Makefile b/Makefile index ad45508..a114053 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ ROOT_DIR := $(shell git rev-parse --show-toplevel) MAIN_DIR := ${ROOT_DIR} COVERAGE_FILE := ${ROOT_DIR}/coverage.txt COVERAGE_HTML := ${ROOT_DIR}/coverage.html -TEST_CMD := GOTEST=true go test -v -race -cover -coverprofile=${COVERAGE_FILE} ./... +TEST_CMD := GOTEST=true OUTPUT_FILE=/dev/null go test -v -race -cover -coverprofile=${COVERAGE_FILE} ./... OPEN_CMD := $(shell if command -v explorer.exe 1>/dev/null; then echo "explorer.exe"; elif uname -s | grep -q Darwin; then echo "open"; else echo "echo"; fi) diff --git a/README.md b/README.md index 2750086..97298d5 100644 --- a/README.md +++ b/README.md @@ -7,18 +7,105 @@ BigQuery table schema struct generator ## generate -```console -$ cd /path/to/your/golang-project-repository +#### How to generate -$ ## Create a directory where bqtableschema will generate the code. -$ mkdir -p bqtableschema -$ cd bqtableschema +```bash +cd /path/to/your/golang-project-repository -$ ## Set the required environment variables. -$ export GOOGLE_APPLICATION_CREDENTIALS=/path/to/serviceaccount/keyfile.json -$ export GCLOUD_PROJECT_ID=bigquery-public-data ## ref. https://console.cloud.google.com/bigquery?p=bigquery-public-data&page=project -$ export BIGQUERY_DATASET=hacker_news ## ref. https://console.cloud.google.com/bigquery?p=bigquery-public-data&d=hacker_news&page=dataset +# Create a directory where bqtableschema will generate the code. +mkdir -p bqtableschema +cd bqtableschema -$ ## generate -$ go run github.com/djeeno/bqtableschema +# Set the required environment variables. +export GOOGLE_APPLICATION_CREDENTIALS=/path/to/serviceaccount/keyfile.json +# Set GCP Project ID ref. https://console.cloud.google.com/bigquery?p=bigquery-public-data&page=project +export GCLOUD_PROJECT_ID=bigquery-public-data +# Set BigQuery Dataset name ref. https://console.cloud.google.com/bigquery?p=bigquery-public-data&d=hacker_news&page=dataset +export BIGQUERY_DATASET=hacker_news +# Set output file +export OUTPUT_FILE=bqtableschema.generated.go + +# generate +go run github.com/djeeno/bqtableschema +``` + +Example generated file content: + +```go +// Code generated by go run github.com/djeeno/bqtableschema; DO NOT EDIT. + +//go:generate go run github.com/djeeno/bqtableschema + +package bqtableschema + +import "time" + +// Comments is BigQuery Table `bigquery-public-data:hacker_news.comments` schema struct. +// Description: +type Comments struct { + Id int64 `bigquery:"id"` + By string `bigquery:"by"` + Author string `bigquery:"author"` + Time int64 `bigquery:"time"` + Time_ts time.Time `bigquery:"time_ts"` + Text string `bigquery:"text"` + Parent int64 `bigquery:"parent"` + Deleted bool `bigquery:"deleted"` + Dead bool `bigquery:"dead"` + Ranking int64 `bigquery:"ranking"` +} + +// Full is BigQuery Table `bigquery-public-data:hacker_news.full` schema struct. +// Description: A full daily update of all the stories and comments in Hacker News. +type Full struct { + Title string `bigquery:"title"` + Url string `bigquery:"url"` + Text string `bigquery:"text"` + Dead bool `bigquery:"dead"` + By string `bigquery:"by"` + Score int64 `bigquery:"score"` + Time int64 `bigquery:"time"` + Timestamp time.Time `bigquery:"timestamp"` + Type string `bigquery:"type"` + Id int64 `bigquery:"id"` + Parent int64 `bigquery:"parent"` + Descendants int64 `bigquery:"descendants"` + Ranking int64 `bigquery:"ranking"` + Deleted bool `bigquery:"deleted"` +} + +// Full_201510 is BigQuery Table `bigquery-public-data:hacker_news.full_201510` schema struct. +// Description: +type Full_201510 struct { + By string `bigquery:"by"` + Score int64 `bigquery:"score"` + Time int64 `bigquery:"time"` + Title string `bigquery:"title"` + Type string `bigquery:"type"` + Url string `bigquery:"url"` + Text string `bigquery:"text"` + Parent int64 `bigquery:"parent"` + Deleted bool `bigquery:"deleted"` + Dead bool `bigquery:"dead"` + Descendants int64 `bigquery:"descendants"` + Id int64 `bigquery:"id"` + Ranking int64 `bigquery:"ranking"` +} + +// Stories is BigQuery Table `bigquery-public-data:hacker_news.stories` schema struct. +// Description: +type Stories struct { + Id int64 `bigquery:"id"` + By string `bigquery:"by"` + Score int64 `bigquery:"score"` + Time int64 `bigquery:"time"` + Time_ts time.Time `bigquery:"time_ts"` + Title string `bigquery:"title"` + Url string `bigquery:"url"` + Text string `bigquery:"text"` + Deleted bool `bigquery:"deleted"` + Dead bool `bigquery:"dead"` + Descendants int64 `bigquery:"descendants"` + Author string `bigquery:"author"` +} ``` diff --git a/main.go b/main.go index 8c4653d..7f6ef9d 100644 --- a/main.go +++ b/main.go @@ -39,18 +39,13 @@ const ( var ( // optValue - optValueProjectID string - optValueDataset string - optValueKeyFile string - optValueOutputPath string + optValueProjectID = flag.String(optNameProjectID, defaultValueEmpty, "") + optValueDataset = flag.String(optNameDataset, defaultValueEmpty, "") + optValueKeyFile = flag.String(optNameKeyFile, defaultValueEmpty, "path to service account json key file") + optValueOutputPath = flag.String(optNameOutputFile, defaultValueEmpty, "path to output the generated code") ) func main() { - flag.StringVar(&optValueProjectID, optNameProjectID, defaultValueEmpty, "") - flag.StringVar(&optValueDataset, optNameDataset, defaultValueEmpty, "") - flag.StringVar(&optValueKeyFile, optNameKeyFile, defaultValueEmpty, "path to service account json key file") - flag.StringVar(&optValueOutputPath, optNameOutputFile, defaultValueEmpty, "path to output the generated code") - flag.Parse() ctx := context.Background() @@ -62,31 +57,36 @@ func main() { // Run is effectively a `main` function. // It is separated from the `main` function because of addressing an issue where` defer` is not executed when `os.Exit` is executed. -func Run(ctx context.Context) error { +func Run(ctx context.Context) (err error) { + flag.Parse() - filePath, err := getOptOrEnvOrDefault(optNameOutputFile, optValueOutputPath, envNameOutputFile, defaultValueOutputFile) + var keyfile string + keyfile, err = getOptOrEnvOrDefault(optNameKeyFile, *optValueKeyFile, envNameGoogleApplicationCredentials, "") if err != nil { return fmt.Errorf("getOptOrEnvOrDefault: %w", err) } - keyfile, err := getOptOrEnvOrDefault(optNameKeyFile, optValueKeyFile, envNameGoogleApplicationCredentials, "") + var project string + project, err = getOptOrEnvOrDefault(optNameProjectID, *optValueProjectID, envNameGCloudProjectID, "") if err != nil { return fmt.Errorf("getOptOrEnvOrDefault: %w", err) } - project, err := getOptOrEnvOrDefault(optNameProjectID, optValueProjectID, envNameGCloudProjectID, "") + var dataset string + dataset, err = getOptOrEnvOrDefault(optNameDataset, *optValueDataset, envNameBigQueryDataset, "") if err != nil { return fmt.Errorf("getOptOrEnvOrDefault: %w", err) } - dataset, err := getOptOrEnvOrDefault(optNameDataset, optValueDataset, envNameBigQueryDataset, "") + var filePath string + filePath, err = getOptOrEnvOrDefault(optNameOutputFile, *optValueOutputPath, envNameOutputFile, defaultValueOutputFile) if err != nil { return fmt.Errorf("getOptOrEnvOrDefault: %w", err) } // set GOOGLE_APPLICATION_CREDENTIALS for Google Cloud SDK if os.Getenv(envNameGoogleApplicationCredentials) != keyfile { - if err := os.Setenv(envNameGoogleApplicationCredentials, keyfile); err != nil { + if err = os.Setenv(envNameGoogleApplicationCredentials, keyfile); err != nil { return fmt.Errorf("os.Setenv: %w", err) } } @@ -96,7 +96,7 @@ func Run(ctx context.Context) error { return fmt.Errorf("bigquery.NewClient: %w", err) } defer func() { - if err := client.Close(); err != nil { + if err = client.Close(); err != nil { warnln("client.Close: " + err.Error()) } }() @@ -107,7 +107,7 @@ func Run(ctx context.Context) error { } // NOTE(djeeno): output - if err := ioutil.WriteFile(filePath, generatedCode, 0644); err != nil { + if err = ioutil.WriteFile(filePath, generatedCode, 0644); err != nil { return fmt.Errorf("ioutil.WriteFile: %w", err) } @@ -132,7 +132,9 @@ package bqtableschema var tail string var importPackages []string for _, table := range tables { - structCode, pkgs, err := generateTableSchemaCode(ctx, table) + var structCode string + var pkgs []string + structCode, pkgs, err = generateTableSchemaCode(ctx, table) if err != nil { warnln("generateTableSchemaCode: " + err.Error()) continue @@ -206,7 +208,8 @@ func generateTableSchemaCode(ctx context.Context, table *bigquery.Table) (genera } structName := capitalizeInitial(table.TableID) - md, err := table.Metadata(ctx) + var md *bigquery.TableMetadata + md, err = table.Metadata(ctx) if err != nil { return "", nil, fmt.Errorf("table.Metadata: %w", err) } @@ -219,7 +222,8 @@ func generateTableSchemaCode(ctx context.Context, table *bigquery.Table) (genera schemas := []*bigquery.FieldSchema(md.Schema) for _, schema := range schemas { - goTypeStr, pkg, err := bigqueryFieldTypeToGoType(schema.Type) + var goTypeStr, pkg string + goTypeStr, pkg, err = bigqueryFieldTypeToGoType(schema.Type) if err != nil { return "", nil, fmt.Errorf("bigqueryFieldTypeToGoType: %w", err) } @@ -236,7 +240,8 @@ func generateTableSchemaCode(ctx context.Context, table *bigquery.Table) (genera func getAllTables(ctx context.Context, client *bigquery.Client, datasetID string) (tables []*bigquery.Table, err error) { tableIterator := client.Dataset(datasetID).Tables(ctx) for { - table, err := tableIterator.Next() + var table *bigquery.Table + table, err = tableIterator.Next() if err != nil { if err == iterator.Done { break @@ -248,13 +253,15 @@ func getAllTables(ctx context.Context, client *bigquery.Client, datasetID string return tables, nil } -func readFile(path string) ([]byte, error) { - file, err := os.Open(path) +func readFile(path string) (content []byte, err error) { + var file *os.File + file, err = os.Open(path) if err != nil { return nil, fmt.Errorf("os.Open: %w", err) } - bytea, err := ioutil.ReadAll(file) + var bytea []byte + bytea, err = ioutil.ReadAll(file) if err != nil { return nil, fmt.Errorf("ioutil.ReadAll: %w", err) } @@ -262,7 +269,7 @@ func readFile(path string) ([]byte, error) { return bytea, nil } -func getOptOrEnvOrDefault(optName, optValue, envName, defaultValue string) (string, error) { +func getOptOrEnvOrDefault(optName, optValue, envName, defaultValue string) (value string, err error) { if optName == "" { return "", fmt.Errorf("optName is empty") } @@ -298,7 +305,7 @@ func infoln(content string) { } func warnln(content string) { - log.Println("WARNING: " + content) + log.Println("WARN: " + content) } func errorln(content string) { diff --git a/main_test.go b/main_test.go index e4e538c..ac35775 100644 --- a/main_test.go +++ b/main_test.go @@ -46,338 +46,367 @@ const ( testNotSupportedFieldType = "notSupportedFieldType" ) -func Test_Run_OK_1(t *testing.T) { - if os.Getenv(envNameGoogleApplicationCredentials) == "" { - t.Skip("WARN: " + envNameGoogleApplicationCredentials + " is not set") - } - - // projectID - backupEnvNameGCloudProjectID, exist := os.LookupEnv(envNameGCloudProjectID) - _ = os.Setenv(envNameGCloudProjectID, testPublicDataProjectID) - defer func() { - if exist { - _ = os.Setenv(envNameGCloudProjectID, backupEnvNameGCloudProjectID) - return +func Test_Run(t *testing.T) { + t.Run("正常系_testPublicDataProjectID_"+testPublicDataProjectID+"_testSupportedDatasetID_"+testSupportedDatasetID, func(t *testing.T) { + if os.Getenv(envNameGoogleApplicationCredentials) == "" { + t.Skip("WARN: " + envNameGoogleApplicationCredentials + " is not set") } - _ = os.Unsetenv(envNameGCloudProjectID) - }() - // datasetID - backupEnvNameBigQueryDatasetValue, exist := os.LookupEnv(envNameBigQueryDataset) - _ = os.Setenv(envNameBigQueryDataset, testSupportedDatasetID) - defer func() { - if exist { - _ = os.Setenv(envNameBigQueryDataset, backupEnvNameBigQueryDatasetValue) - return - } - _ = os.Unsetenv(envNameBigQueryDataset) - }() + // projectID + backupEnvNameGCloudProjectID, exist := os.LookupEnv(envNameGCloudProjectID) + _ = os.Setenv(envNameGCloudProjectID, testPublicDataProjectID) + defer func() { + if exist { + _ = os.Setenv(envNameGCloudProjectID, backupEnvNameGCloudProjectID) + return + } + _ = os.Unsetenv(envNameGCloudProjectID) + }() + + // datasetID + backupEnvNameBigQueryDatasetValue, exist := os.LookupEnv(envNameBigQueryDataset) + _ = os.Setenv(envNameBigQueryDataset, testSupportedDatasetID) + defer func() { + if exist { + _ = os.Setenv(envNameBigQueryDataset, backupEnvNameBigQueryDatasetValue) + return + } + _ = os.Unsetenv(envNameBigQueryDataset) + }() - var ( - ctx = context.Background() - ) - if err := Run(ctx); err != nil { - t.Error(err) - } + var ( + ctx = context.Background() + ) + if err := Run(ctx); err != nil { + t.Error(err) + } + }) } -func Test_Generate_OK_1(t *testing.T) { - if os.Getenv(envNameGoogleApplicationCredentials) == "" { - t.Skip("WARN: " + envNameGoogleApplicationCredentials + " is not set") - } +func Test_Generate(t *testing.T) { + t.Run("正常系_testSupportedDatasetID_"+testSupportedDatasetID, func(t *testing.T) { + if os.Getenv(envNameGoogleApplicationCredentials) == "" { + t.Skip("WARN: " + envNameGoogleApplicationCredentials + " is not set") + } + + var ( + ctx = context.Background() + client, _ = bigquery.NewClient(ctx, testPublicDataProjectID) + ) - var ( - ctx = context.Background() - client, _ = bigquery.NewClient(ctx, testPublicDataProjectID) - ) - _, err := Generate(ctx, client, testSupportedDatasetID) - if err != nil { - t.Error(err) - } -} + _, err := Generate(ctx, client, testSupportedDatasetID) + if err != nil { + t.Error(err) + } + }) -func Test_Generate_OK_2(t *testing.T) { - if os.Getenv(envNameGoogleApplicationCredentials) == "" { - t.Skip("WARN: " + envNameGoogleApplicationCredentials + " is not set") - } + t.Run("正常系_testNotSupportedDatasetID_"+testNotSupportedDatasetID, func(t *testing.T) { + if os.Getenv(envNameGoogleApplicationCredentials) == "" { + t.Skip("WARN: " + envNameGoogleApplicationCredentials + " is not set") + } - var ( - ctx = context.Background() - client, _ = bigquery.NewClient(ctx, testPublicDataProjectID) - ) - _, err := Generate(ctx, client, testNotSupportedDatasetID) - if err != nil { - t.Error(err) - } -} + var ( + ctx = context.Background() + client, _ = bigquery.NewClient(ctx, testPublicDataProjectID) + ) -func Test_generateImportPackagesCode_OK_1(t *testing.T) { - var ( - testImportsSlice = []string{} - ) - generatedCode := generateImportPackagesCode(testImportsSlice) - if generatedCode != testEmptyString { - t.Error() - } + _, err := Generate(ctx, client, testNotSupportedDatasetID) + if err != nil { + t.Error(err) + } + }) } -func Test_generateImportPackagesCode_OK_2(t *testing.T) { - const ( - testImportCode = "import \"time\"\n\n" - ) - var ( - testImportsSlice = []string{"time"} - ) - generatedCode := generateImportPackagesCode(testImportsSlice) +func Test_generateImportPackagesCode(t *testing.T) { + t.Run("正常系_import_nothing", func(t *testing.T) { + const ( + // 正しい出力 + testImportCode = "" + ) + var ( + testImportsSlice = []string{} + ) + + generatedCode := generateImportPackagesCode(testImportsSlice) + if generatedCode != testImportCode { + t.Error() + } + }) - if generatedCode != testImportCode { + t.Run("正常系_import_time", func(t *testing.T) { + const ( + // 正しい出力 + testImportCode = "import \"time\"\n\n" + ) var ( - rr = strings.NewReplacer("\n", "\\n", "`", "\\`") - want = rr.Replace(testImportCode) - current = rr.Replace(generatedCode) + testImportsSlice = []string{"time"} ) - t.Error("generateImportPackagesCode: want=`" + want + "` current=`" + current + "`") - } -} + generatedCode := generateImportPackagesCode(testImportsSlice) + + if generatedCode != testImportCode { + var ( + rr = strings.NewReplacer("\n", "\\n", "`", "\\`") + want = rr.Replace(testImportCode) + current = rr.Replace(generatedCode) + ) + t.Error("generateImportPackagesCode: want=`" + want + "` current=`" + current + "`") + } + }) -func Test_generateImportPackagesCode_OK_3(t *testing.T) { - const ( - testImportCode = `import ( + t.Run("正常系_import_math/big_time", func(t *testing.T) { + const ( + // 正しい出力 + testImportCode = `import ( "math/big" "time" ) ` - ) - var ( - testImportsSlice = []string{"math/big", "time"} - ) - generatedCode := generateImportPackagesCode(testImportsSlice) - - if generatedCode != testImportCode { + ) var ( - rr = strings.NewReplacer("\n", "\\n", "`", "\\`") - want = rr.Replace(testImportCode) - current = rr.Replace(generatedCode) + testImportsSlice = []string{"math/big", "time"} ) - t.Error("generateImportPackagesCode: want=`" + want + "` current=`" + current + "`") - } + generatedCode := generateImportPackagesCode(testImportsSlice) + + if generatedCode != testImportCode { + var ( + rr = strings.NewReplacer("\n", "\\n", "`", "\\`") + want = rr.Replace(testImportCode) + current = rr.Replace(generatedCode) + ) + t.Error("generateImportPackagesCode: want=`" + want + "` current=`" + current + "`") + } + }) } -func Test_generateTableSchemaCode_OK(t *testing.T) { - var ( - ctx = context.Background() - ) +func Test_generateTableSchemaCode(t *testing.T) { + t.Run("正常系_testPublicDataProjectID_testPublicDataProjectID", func(t *testing.T) { + var ( + ctx = context.Background() + ) - if os.Getenv(envNameGoogleApplicationCredentials) == "" { - t.Skip("WARN: " + envNameGoogleApplicationCredentials + " is not set") - } + if os.Getenv(envNameGoogleApplicationCredentials) == "" { + t.Skip("WARN: " + envNameGoogleApplicationCredentials + " is not set") + } - var ( - ngClient, _ = bigquery.NewClient(ctx, testPublicDataProjectID) - ngTableIterator = ngClient.Dataset(testSupportedDatasetID).Tables(ctx) - ) + var ( + ngClient, _ = bigquery.NewClient(ctx, testPublicDataProjectID) + ngTableIterator = ngClient.Dataset(testSupportedDatasetID).Tables(ctx) + ) - for { - table, err := ngTableIterator.Next() - if err == iterator.Done { - break - } - if err != nil { - t.Error(err) - } - if _, _, err := generateTableSchemaCode(ctx, table); err != nil { - t.Error(err) + for { + table, err := ngTableIterator.Next() + if err == iterator.Done { + break + } + if err != nil { + t.Error(err) + } + if _, _, err := generateTableSchemaCode(ctx, table); err != nil { + t.Error(err) + } } - } -} + }) -func Test_generateTableSchemaCode_NG_1(t *testing.T) { - var ( - ctx = context.Background() - ngTable = &bigquery.Table{ - ProjectID: testProjectNotFound, - DatasetID: testDatasetNotFound, - TableID: testEmptyString, + t.Run("異常系_testProjectNotFound_testDatasetNotFound", func(t *testing.T) { + var ( + ctx = context.Background() + ngTable = &bigquery.Table{ + ProjectID: testProjectNotFound, + DatasetID: testDatasetNotFound, + TableID: testEmptyString, + } + ) + if _, _, err := generateTableSchemaCode(ctx, ngTable); err == nil { + t.Error(err) } - ) - if _, _, err := generateTableSchemaCode(ctx, ngTable); err == nil { - t.Error(err) - } -} + }) -func Test_generateTableSchemaCode_NG_2(t *testing.T) { - var ( - ctx = context.Background() - ) + t.Run("異常系_testProjectNotFound_testNotSupportedDatasetID", func(t *testing.T) { + var ( + ctx = context.Background() + ) - if os.Getenv(envNameGoogleApplicationCredentials) == "" { - t.Skip("WARN: " + envNameGoogleApplicationCredentials + " is not set") - } + if os.Getenv(envNameGoogleApplicationCredentials) == "" { + t.Skip("WARN: " + envNameGoogleApplicationCredentials + " is not set") + } - var ( - ngClient, _ = bigquery.NewClient(ctx, testPublicDataProjectID) - ngTable, _ = ngClient.Dataset(testNotSupportedDatasetID).Tables(ctx).Next() - ) + var ( + ngClient, _ = bigquery.NewClient(ctx, testPublicDataProjectID) + ngTable, _ = ngClient.Dataset(testNotSupportedDatasetID).Tables(ctx).Next() + ) - ngTable.ProjectID = testProjectNotFound - if _, _, err := generateTableSchemaCode(ctx, ngTable); err == nil { - t.Error(err) - } -} + ngTable.ProjectID = testProjectNotFound + if _, _, err := generateTableSchemaCode(ctx, ngTable); err == nil { + t.Error(err) + } + }) -func Test_generateTableSchemaCode_NG_3(t *testing.T) { - var ( - ctx = context.Background() - ) + t.Run("異常系_testPublicDataProjectID_testNotSupportedDatasetID_testSubStrFieldTypeNotSupported", func(t *testing.T) { + var ( + ctx = context.Background() + ) - if os.Getenv(envNameGoogleApplicationCredentials) == "" { - t.Skip("WARN: " + envNameGoogleApplicationCredentials + " is not set") - } + if os.Getenv(envNameGoogleApplicationCredentials) == "" { + t.Skip("WARN: " + envNameGoogleApplicationCredentials + " is not set") + } - var ( - ngClient, _ = bigquery.NewClient(ctx, testPublicDataProjectID) - ngTableIterator = ngClient.Dataset(testNotSupportedDatasetID).Tables(ctx) - ) + var ( + ngClient, _ = bigquery.NewClient(ctx, testPublicDataProjectID) + ngTableIterator = ngClient.Dataset(testNotSupportedDatasetID).Tables(ctx) + ) - for { - table, err := ngTableIterator.Next() - if err == iterator.Done { - break - } - if err != nil { - t.Error(err) - } - if _, _, err := generateTableSchemaCode(ctx, table); err != nil { - // NOTE(djeeno): "bigquery.FieldType not supported." 以外のエラーが出たら Fail - if !strings.Contains(err.Error(), testSubStrFieldTypeNotSupported) { + for { + table, err := ngTableIterator.Next() + if err == iterator.Done { + break + } + if err != nil { t.Error(err) } - // NOTE(djeeno): ここまで来たら、確認したいことは確認済み。 - // ref. https://github.com/djeeno/bqtableschema/blob/260524ce0ae2dd5bdcbdd57446cdd8c140326ca4/main.go#L212 - return + if _, _, err := generateTableSchemaCode(ctx, table); err != nil { + // NOTE(djeeno): "bigquery.FieldType not supported." 以外のエラーが出たら Fail + if !strings.Contains(err.Error(), testSubStrFieldTypeNotSupported) { + t.Error(err) + } + // NOTE(djeeno): ここまで来たら、確認したいことは確認済み。 + // ref. https://github.com/djeeno/bqtableschema/blob/260524ce0ae2dd5bdcbdd57446cdd8c140326ca4/main.go#L212 + return + } } - } + }) } -func Test_getAllTables_OK(t *testing.T) { - if os.Getenv(envNameGoogleApplicationCredentials) == "" { - t.Skip("WARN: " + envNameGoogleApplicationCredentials + " is not set") - } +func Test_getAllTables(t *testing.T) { + t.Run("正常系_testPublicDataProjectID_testSupportedDatasetID", func(t *testing.T) { - var ( - ctx = context.Background() - okClient, _ = bigquery.NewClient(ctx, testPublicDataProjectID) - ) + if os.Getenv(envNameGoogleApplicationCredentials) == "" { + t.Skip("WARN: " + envNameGoogleApplicationCredentials + " is not set") + } - if _, err := getAllTables(ctx, okClient, testSupportedDatasetID); err != nil { - t.Error(err) - } -} + var ( + ctx = context.Background() + okClient, _ = bigquery.NewClient(ctx, testPublicDataProjectID) + ) -func Test_getAllTables_NG(t *testing.T) { - backupValue, exist := os.LookupEnv(envNameGoogleApplicationCredentials) - _ = os.Setenv(envNameGoogleApplicationCredentials, testGoogleApplicationCredentials) - defer func() { - if exist { - _ = os.Setenv(envNameGoogleApplicationCredentials, backupValue) - return + if _, err := getAllTables(ctx, okClient, testSupportedDatasetID); err != nil { + t.Error(err) } - _ = os.Unsetenv(envNameGoogleApplicationCredentials) - }() + }) - var ( - ctx = context.Background() - ngClient, _ = bigquery.NewClient(ctx, testProjectNotFound) - ) + t.Run("異常系_testProjectNotFound_testDatasetNotFound", func(t *testing.T) { - if _, err := getAllTables(ctx, ngClient, testDatasetNotFound); err == nil { - t.Error(err) - } -} + backupValue, exist := os.LookupEnv(envNameGoogleApplicationCredentials) + _ = os.Setenv(envNameGoogleApplicationCredentials, testGoogleApplicationCredentials) + defer func() { + if exist { + _ = os.Setenv(envNameGoogleApplicationCredentials, backupValue) + return + } + _ = os.Unsetenv(envNameGoogleApplicationCredentials) + }() -func Test_readFile_OK(t *testing.T) { - if _, err := readFile(testProbablyExistsPath); err != nil { - t.Error(err) - } -} + var ( + ctx = context.Background() + ngClient, _ = bigquery.NewClient(ctx, testProjectNotFound) + ) -func Test_readFile_NG_1(t *testing.T) { - if _, err := readFile(testErrNoSuchFileOrDirectoryPath); err == nil { - t.Error(err) - } + if _, err := getAllTables(ctx, ngClient, testDatasetNotFound); err == nil { + t.Error(err) + } + }) } -func Test_readFile_NG_2(t *testing.T) { - if _, err := readFile(testErrIsADirectoryPath); err == nil { - t.Error(err) - } -} +func Test_readFile(t *testing.T) { + t.Run("正常系_testProbablyExistsPath", func(t *testing.T) { + if _, err := readFile(testProbablyExistsPath); err != nil { + t.Error(err) + } + }) -func Test_getOptOrEnvOrDefault_OK_1(t *testing.T) { - v, err := getOptOrEnvOrDefault(testOptName, testOptValue, testEnvName, testDefaultValue) - if err != nil { - t.Error(err) - } - if v != testOptValue { - t.Error(err) - } -} -func Test_getOptOrEnvOrDefault_OK_2(t *testing.T) { - if err := os.Setenv(testEnvName, testEnvValue); err != nil { - t.Error(err) - } - v, err := getOptOrEnvOrDefault(testOptName, testEmptyString, testEnvName, testDefaultValue) - if err != nil { - t.Error(err) - } - if v != testEnvValue { - t.Error(err) - } - if err := os.Unsetenv(testEnvName); err != nil { - t.Error(err) - } + t.Run("異常系_testErrNoSuchFileOrDirectoryPath", func(t *testing.T) { + if _, err := readFile(testErrNoSuchFileOrDirectoryPath); err == nil { + t.Error(err) + } + }) + t.Run("異常系_testErrIsADirectoryPath", func(t *testing.T) { + if _, err := readFile(testErrIsADirectoryPath); err == nil { + t.Error(err) + } + }) } -func Test_getOptOrEnvOrDefault_OK_3(t *testing.T) { - v, err := getOptOrEnvOrDefault(testOptName, testEmptyString, testEnvName, testDefaultValue) - if err != nil { - t.Error(err) - } - if v != testDefaultValue { - t.Error(err) - } -} +func Test_getOptOrEnvOrDefault(t *testing.T) { + t.Run("正常系_testOptValue", func(t *testing.T) { + v, err := getOptOrEnvOrDefault(testOptName, testOptValue, testEnvName, testDefaultValue) + if err != nil { + t.Error(err) + } + if v != testOptValue { + t.Error(err) + } + }) -func Test_getOptOrEnvOrDefault_NG_1(t *testing.T) { - v, err := getOptOrEnvOrDefault(testEmptyString, testEmptyString, testEmptyString, testEmptyString) - if err == nil { - t.Error(err) - } - if v != testEmptyString { - t.Error(err) - } -} + t.Run("正常系_testEnvValue", func(t *testing.T) { + if err := os.Setenv(testEnvName, testEnvValue); err != nil { + t.Error(err) + } + v, err := getOptOrEnvOrDefault(testOptName, testEmptyString, testEnvName, testDefaultValue) + if err != nil { + t.Error(err) + } + if v != testEnvValue { + t.Error(err) + } + if err := os.Unsetenv(testEnvName); err != nil { + t.Error(err) + } + }) + + t.Run("正常系_testDefaultValue", func(t *testing.T) { + v, err := getOptOrEnvOrDefault(testOptName, testEmptyString, testEnvName, testDefaultValue) + if err != nil { + t.Error(err) + } + if v != testDefaultValue { + t.Error(err) + } + }) + + t.Run("異常系_testEmptyString_all", func(t *testing.T) { + v, err := getOptOrEnvOrDefault(testEmptyString, testEmptyString, testEmptyString, testEmptyString) + if err == nil { + t.Error(err) + } + if v != testEmptyString { + t.Error(err) + } + }) -func Test_getOptOrEnvOrDefault_NG_2(t *testing.T) { - v, err := getOptOrEnvOrDefault(testOptName, testEmptyString, testEnvName, testEmptyString) - if err == nil { - t.Error(err) - } - if v != testEmptyString { - t.Error(err) - } + t.Run("異常系_testEmptyString", func(t *testing.T) { + v, err := getOptOrEnvOrDefault(testOptName, testEmptyString, testEnvName, testEmptyString) + if err == nil { + t.Error(err) + } + if v != testEmptyString { + t.Error(err) + } + }) } func Test_capitalizeInitial(t *testing.T) { - if capitalizeInitial(testEmptyString) != testEmptyString { - t.Error() - } + t.Run("正常系_testEmptyString", func(t *testing.T) { + if capitalizeInitial(testEmptyString) != testEmptyString { + t.Error() + } + }) - if capitalizeInitial(testNotCapitalized) != testCapitalized { - t.Error() - } + t.Run("正常系_testCapitalized", func(t *testing.T) { + if capitalizeInitial(testNotCapitalized) != testCapitalized { + t.Error() + } + }) } func Test_infoln(t *testing.T) { @@ -435,23 +464,27 @@ func Test_bigqueryFieldTypeToGoType(t *testing.T) { } ) - for bigqueryFieldType, typeOf := range supportedBigqueryFieldTypes { - goType, _, err := bigqueryFieldTypeToGoType(bigqueryFieldType) - if err != nil { - t.Error(err) - } - if goType != typeOf { - t.Error() + t.Run("正常系_supportedBigqueryFieldTypes", func(t *testing.T) { + for bigqueryFieldType, typeOf := range supportedBigqueryFieldTypes { + goType, _, err := bigqueryFieldTypeToGoType(bigqueryFieldType) + if err != nil { + t.Error(err) + } + if goType != typeOf { + t.Error() + } } - } + }) - for bigqueryFieldType, typeOf := range unsupportedBigqueryFieldTypes { - goType, _, err := bigqueryFieldTypeToGoType(bigqueryFieldType) - if err == nil { - t.Error(err) - } - if goType != typeOf { - t.Error() + t.Run("異常系_unsupportedBigqueryFieldTypes", func(t *testing.T) { + for bigqueryFieldType, typeOf := range unsupportedBigqueryFieldTypes { + goType, _, err := bigqueryFieldTypeToGoType(bigqueryFieldType) + if err == nil { + t.Error(err) + } + if goType != typeOf { + t.Error() + } } - } + }) }