github.com/mithrandie/csvq@v1.18.1/lib/query/table_path_test.go (about)

     1  package query
     2  
     3  import (
     4  	"context"
     5  	"reflect"
     6  	"testing"
     7  
     8  	"github.com/mithrandie/csvq/lib/parser"
     9  )
    10  
    11  var parseTableNameTests = []struct {
    12  	Table  parser.Table
    13  	Result string
    14  	Error  string
    15  }{
    16  	{
    17  		Table: parser.Table{
    18  			Object: parser.Identifier{Literal: "table.csv"},
    19  			As:     parser.Token{Token: parser.AS, Literal: "as"},
    20  			Alias:  parser.Identifier{Literal: "alias"},
    21  		},
    22  		Result: "alias",
    23  	},
    24  	{
    25  		Table: parser.Table{
    26  			Object: parser.Identifier{Literal: "/path/to/table.csv"},
    27  		},
    28  		Result: "table",
    29  	},
    30  	{
    31  		Table: parser.Table{
    32  			Object: parser.Stdin{},
    33  		},
    34  		Result: "STDIN",
    35  	},
    36  	{
    37  		Table: parser.Table{
    38  			Object: parser.Subquery{
    39  				Query: parser.SelectQuery{
    40  					SelectEntity: parser.SelectEntity{
    41  						SelectClause: parser.SelectClause{
    42  							Fields: []parser.QueryExpression{
    43  								parser.NewIntegerValueFromString("1"),
    44  							},
    45  						},
    46  						FromClause: parser.FromClause{
    47  							Tables: []parser.QueryExpression{parser.Dual{}},
    48  						},
    49  					},
    50  				},
    51  			},
    52  		},
    53  		Result: "",
    54  	},
    55  	{
    56  		Table: parser.Table{
    57  			Object: parser.FormatSpecifiedFunction{
    58  				Type:          parser.Token{Token: parser.FIXED, Literal: "fixed"},
    59  				FormatElement: parser.NewStringValue("[1, 2, 3]"),
    60  				Path:          parser.Identifier{Literal: "fixed_length.dat", Quoted: true},
    61  				Args:          nil,
    62  			},
    63  		},
    64  		Result: "fixed_length",
    65  	},
    66  	{
    67  		Table: parser.Table{
    68  			Object: parser.TableFunction{
    69  				Name: "file",
    70  				Args: []parser.QueryExpression{parser.NewStringValue("table.csv")},
    71  			},
    72  		},
    73  		Result: "table",
    74  	},
    75  	{
    76  		Table: parser.Table{
    77  			Object: parser.TableFunction{
    78  				Name: "file",
    79  			},
    80  		},
    81  		Error: "function FILE takes exactly 1 argument",
    82  	},
    83  }
    84  
    85  func TestParseTableName(t *testing.T) {
    86  	ctx := context.Background()
    87  	scope := NewReferenceScope(TestTx)
    88  
    89  	for _, v := range parseTableNameTests {
    90  		name, err := ParseTableName(ctx, scope, v.Table)
    91  
    92  		if err != nil {
    93  			if len(v.Error) < 1 {
    94  				t.Errorf("%s: unexpected error %q", v.Table.String(), err)
    95  			} else if err.Error() != v.Error {
    96  				t.Errorf("%s: error %q, want error %q", v.Table.String(), err.Error(), v.Error)
    97  			}
    98  			continue
    99  		}
   100  		if 0 < len(v.Error) {
   101  			t.Errorf("%s: no error, want error %q", v.Table.String(), v.Error)
   102  			continue
   103  		}
   104  
   105  		if name.Literal != v.Result {
   106  			t.Errorf("%s: \n result = %q,\n expect = %q", v.Table.String(), name.Literal, v.Result)
   107  		}
   108  	}
   109  }
   110  
   111  var convertTableFunctionTests = []struct {
   112  	Name          string
   113  	TableFunction parser.TableFunction
   114  	Result        parser.QueryExpression
   115  	Error         string
   116  }{
   117  	{
   118  		Name: "Convert FILE function",
   119  		TableFunction: parser.TableFunction{
   120  			Name: "file",
   121  			Args: []parser.QueryExpression{
   122  				parser.NewStringValue("./table.csv"),
   123  			},
   124  		},
   125  		Result: parser.Identifier{
   126  			Literal: "./table.csv",
   127  		},
   128  	},
   129  	{
   130  		Name: "Argument Length Error in FILE function",
   131  		TableFunction: parser.TableFunction{
   132  			Name: "file",
   133  			Args: []parser.QueryExpression{
   134  				parser.NewStringValue("./table.csv"),
   135  				parser.NewStringValue("./table.csv"),
   136  			},
   137  		},
   138  		Error: "function FILE takes exactly 1 argument",
   139  	},
   140  	{
   141  		Name: "First argument must be a string in FILE function",
   142  		TableFunction: parser.TableFunction{
   143  			Name: "file",
   144  			Args: []parser.QueryExpression{
   145  				parser.NewNullValue(),
   146  			},
   147  		},
   148  		Error: "the first argument must be a string for function FILE",
   149  	},
   150  	{
   151  		Name: "Convert INLINE function",
   152  		TableFunction: parser.TableFunction{
   153  			Name: "inline",
   154  			Args: []parser.QueryExpression{
   155  				parser.NewStringValue("./table.csv"),
   156  			},
   157  		},
   158  		Result: parser.Identifier{
   159  			Literal: "./table.csv",
   160  		},
   161  	},
   162  	{
   163  		Name: "Convert URL function",
   164  		TableFunction: parser.TableFunction{
   165  			Name: "url",
   166  			Args: []parser.QueryExpression{
   167  				parser.NewStringValue("https://example.com"),
   168  			},
   169  		},
   170  		Result: parser.Url{
   171  			Raw: "https://example.com",
   172  		},
   173  	},
   174  	{
   175  		Name: "First argument must be a string in URL function",
   176  		TableFunction: parser.TableFunction{
   177  			Name: "url",
   178  			Args: []parser.QueryExpression{
   179  				parser.NewNullValue(),
   180  			},
   181  		},
   182  		Error: "the first argument must be a string for function URL",
   183  	},
   184  	{
   185  		Name: "Convert DATA function",
   186  		TableFunction: parser.TableFunction{
   187  			Name: "data",
   188  			Args: []parser.QueryExpression{
   189  				parser.NewStringValue("1,a\n2,b"),
   190  			},
   191  		},
   192  		Result: DataObject{
   193  			Raw: "1,a\n2,b",
   194  		},
   195  	},
   196  	{
   197  		Name: "First argument must be a string in DATA function",
   198  		TableFunction: parser.TableFunction{
   199  			Name: "data",
   200  			Args: []parser.QueryExpression{
   201  				parser.NewNullValue(),
   202  			},
   203  		},
   204  		Error: "the first argument must be a string for function DATA",
   205  	},
   206  	{
   207  		Name: "Invalid Function Name Error",
   208  		TableFunction: parser.TableFunction{
   209  			Name: "invalid",
   210  			Args: []parser.QueryExpression{
   211  				parser.NewStringValue("1,a\n2,b"),
   212  			},
   213  		},
   214  		Error: "function INVALID does not exist",
   215  	},
   216  }
   217  
   218  func TestConvertTableFunction(t *testing.T) {
   219  	ctx := context.Background()
   220  	scope := NewReferenceScope(TestTx)
   221  
   222  	for _, v := range convertTableFunctionTests {
   223  		expr, err := ConvertTableFunction(ctx, scope, v.TableFunction)
   224  
   225  		if err != nil {
   226  			if len(v.Error) < 1 {
   227  				t.Errorf("%s: unexpected error %q", v.Name, err)
   228  			} else if err.Error() != v.Error {
   229  				t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error)
   230  			}
   231  			continue
   232  		}
   233  		if 0 < len(v.Error) {
   234  			t.Errorf("%s: no error, want error %q", v.Name, v.Error)
   235  			continue
   236  		}
   237  
   238  		if !reflect.DeepEqual(expr, v.Result) {
   239  			t.Errorf("%s: \n result = %v,\n expect = %v", v.Name, expr, v.Result)
   240  		}
   241  	}
   242  }
   243  
   244  var convertUrlExprTests = []struct {
   245  	Name   string
   246  	Url    parser.Url
   247  	Result parser.QueryExpression
   248  	Error  string
   249  }{
   250  	{
   251  		Name: "Convert URL to HttpObject",
   252  		Url: parser.Url{
   253  			Raw: "https://example.com/おなかすいた/csv",
   254  		},
   255  		Result: HttpObject{
   256  			URL: "https://example.com/%E3%81%8A%E3%81%AA%E3%81%8B%E3%81%99%E3%81%84%E3%81%9F/csv",
   257  		},
   258  	},
   259  	{
   260  		Name: "Convert Absolute File Path to Identifier",
   261  		Url: parser.Url{
   262  			Raw: "file:///home/my dir/data/foo.csv",
   263  		},
   264  		Result: parser.Identifier{
   265  			Literal: "/home/my dir/data/foo.csv",
   266  		},
   267  	},
   268  	{
   269  		Name: "Convert Absolute File Path with URL Encoding to Identifier",
   270  		Url: parser.Url{
   271  			Raw: "file:///home/my%20dir/data/foo.csv",
   272  		},
   273  		Result: parser.Identifier{
   274  			Literal: "/home/my dir/data/foo.csv",
   275  		},
   276  	},
   277  	{
   278  		Name: "Convert Relative File Path to Identifier",
   279  		Url: parser.Url{
   280  			Raw: "file:./data/foo.csv",
   281  		},
   282  		Result: parser.Identifier{
   283  			Literal: "./data/foo.csv",
   284  		},
   285  	},
   286  	{
   287  		Name: "Unsupported URL Scheme",
   288  		Url: parser.Url{
   289  			Raw: "invalid:./data/foo.csv",
   290  		},
   291  		Error: "url scheme invalid is not supported",
   292  	},
   293  }
   294  
   295  func TestConvertUrlExpr(t *testing.T) {
   296  	for _, v := range convertUrlExprTests {
   297  		expr, err := ConvertUrlExpr(v.Url)
   298  
   299  		if err != nil {
   300  			if len(v.Error) < 1 {
   301  				t.Errorf("%s: unexpected error %q", v.Name, err)
   302  			} else if err.Error() != v.Error {
   303  				t.Errorf("%s: error %q, want error %q", v.Name, err.Error(), v.Error)
   304  			}
   305  			continue
   306  		}
   307  		if 0 < len(v.Error) {
   308  			t.Errorf("%s: no error, want error %q", v.Name, v.Error)
   309  			continue
   310  		}
   311  
   312  		if !reflect.DeepEqual(expr, v.Result) {
   313  			t.Errorf("%s: \n result = %v,\n expect = %v", v.Name, expr, v.Result)
   314  		}
   315  	}
   316  }