github.com/everdrone/grab@v0.1.7-0.20230416223925-40674b995521/internal/utils/parse_urls_test.go (about)

     1  package utils
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"reflect"
     7  	"testing"
     8  
     9  	tu "github.com/everdrone/grab/testutils"
    10  	"github.com/hashicorp/hcl/v2"
    11  	"golang.org/x/exp/slices"
    12  )
    13  
    14  func TestIsValidURL(t *testing.T) {
    15  	tests := []struct {
    16  		URL  string
    17  		Want bool
    18  		Name string
    19  	}{
    20  		{URL: "", Want: false, Name: "empty"},
    21  		{URL: "/foo/bar", Want: false, Name: "unix absolute path"},
    22  		{URL: "://foo/bar", Want: false, Name: "no scheme"},
    23  		{URL: "https://foo/bar", Want: true, Name: "no dot com ssl"},
    24  		{URL: "tcp://foo/bar", Want: true, Name: "tcp no dot com"},
    25  		{URL: "https://foo.com/bar", Want: true, Name: "valid ssl"},
    26  		{URL: "1http://anything.com/fails", Want: false, Name: "invalid scheme"},
    27  		{URL: "tcp://foo.com/bar", Want: true, Name: "valid tcp"},
    28  		{URL: "c:\\windows\\bad", Want: false, Name: "windows absolute"},
    29  		{URL: "\\unix\\good", Want: false, Name: "windows absolute without drive"},
    30  		{URL: "unix\\good", Want: false, Name: "windows relative"},
    31  		{URL: "foo/bar", Want: false, Name: "unix relative"},
    32  		{URL: "../foo/bar", Want: false, Name: "unix relative parent"},
    33  		{URL: "~/foo/bar", Want: false, Name: "unix home directory"},
    34  	}
    35  
    36  	for _, tt := range tests {
    37  		t.Run(tt.Name, func(t *testing.T) {
    38  			_, got := IsValidURL(tt.URL)
    39  			if got != tt.Want {
    40  				t.Errorf("got: %v, want: %v", got, tt.Want)
    41  			}
    42  		})
    43  	}
    44  }
    45  
    46  func TestParseURLList(t *testing.T) {
    47  	tests := []struct {
    48  		Name      string
    49  		Input     string
    50  		Filename  string
    51  		Want      []string
    52  		HasErrors bool
    53  		WantDiags hcl.Diagnostics
    54  	}{
    55  		{
    56  			Name:      "empty",
    57  			Input:     "",
    58  			Want:      []string{},
    59  			HasErrors: false,
    60  			WantDiags: nil,
    61  		},
    62  		{
    63  			Name: "all comments",
    64  			Input: `// https://example.com
    65  # https://example.com
    66  ;https://example.com
    67  
    68  # this is ignored as well
    69  `,
    70  			Want:      []string{},
    71  			HasErrors: false,
    72  			WantDiags: nil,
    73  		},
    74  		{
    75  			Name: "only one",
    76  			Input: `// https://example.com
    77  https://example.com
    78  ;https://example.com
    79  
    80  # this is ignored as well
    81  `,
    82  			Want: []string{
    83  				"https://example.com",
    84  			},
    85  			HasErrors: false,
    86  			WantDiags: nil,
    87  		},
    88  		{
    89  			Name:  "removes fragment",
    90  			Input: `https://example.com/foo#bar`,
    91  			Want: []string{
    92  				"https://example.com/foo",
    93  			},
    94  			HasErrors: false,
    95  			WantDiags: nil,
    96  		},
    97  		{
    98  			Name:      "invalid url",
    99  			Input:     `not-an-url lol`,
   100  			Want:      nil,
   101  			HasErrors: true,
   102  			WantDiags: hcl.Diagnostics{
   103  				&hcl.Diagnostic{
   104  					Severity: hcl.DiagError,
   105  					Summary:  "Invalid URL",
   106  					Detail:   "The string 'not-an-url lol' is not a valid url.",
   107  					Subject: &hcl.Range{
   108  						Filename: "list.txt",
   109  						Start:    hcl.Pos{Line: 1, Column: 1},
   110  						End:      hcl.Pos{Line: 1, Column: len("not-an-url lol") + 1},
   111  					},
   112  				},
   113  			},
   114  		},
   115  	}
   116  
   117  	for _, test := range tests {
   118  		t.Run(test.Name, func(t *testing.T) {
   119  			urls, diags := ParseURLList(test.Input, "list.txt")
   120  
   121  			if diags.HasErrors() != test.HasErrors {
   122  				t.Errorf("got: %v, want: %v", diags.HasErrors(), test.HasErrors)
   123  			}
   124  
   125  			if !diags.HasErrors() && !reflect.DeepEqual(urls, test.Want) {
   126  				t.Errorf("got: %v, want: %v", urls, test.Want)
   127  			}
   128  
   129  			if !diags.HasErrors() && !reflect.DeepEqual(diags, test.WantDiags) {
   130  				t.Errorf("got: %v, want: %v", diags, test.WantDiags)
   131  			}
   132  		})
   133  	}
   134  }
   135  
   136  func TestGetURLsFromArgs(t *testing.T) {
   137  	initialWd, _ := os.Getwd()
   138  	defer func() {
   139  		_ = os.Chdir(initialWd)
   140  	}()
   141  
   142  	root := tu.GetOSRoot()
   143  	Fs, Io, Wd = tu.SetupMemMapFs(root)
   144  
   145  	Fs.MkdirAll(filepath.Join(root, "other", "directory"), os.ModePerm)
   146  	Fs.MkdirAll(filepath.Join(root, "tmp"), os.ModePerm)
   147  	Io.WriteFile(Fs, filepath.Join(root, "restricted__r.txt"), []byte("not readable"), os.ModePerm)
   148  	Io.WriteFile(Fs, filepath.Join(root, "tmp", "list.ini"), []byte(`// https://example.com
   149  https://example.com
   150  https://more.com?foo=bar#baz
   151  ;https://example.com
   152  
   153  # this is ignored as well
   154  `), os.ModePerm)
   155  	Io.WriteFile(Fs, filepath.Join(root, "tmp", "invalid.ini"), []byte(`// https://example.com
   156  \x000
   157  ;https://example.com
   158  
   159  # this is ignored as well
   160  `), os.ModePerm)
   161  
   162  	tests := []struct {
   163  		Name      string
   164  		Args      []string
   165  		Want      []string
   166  		WantDiags hcl.Diagnostics
   167  	}{
   168  		{
   169  			Name:      "empty",
   170  			Args:      []string{},
   171  			Want:      []string{},
   172  			WantDiags: nil,
   173  		},
   174  		{
   175  			Name: "file with comments",
   176  			Args: []string{filepath.Join(root, "tmp", "list.ini")},
   177  			Want: []string{
   178  				"https://example.com",
   179  				"https://more.com?foo=bar",
   180  			},
   181  			WantDiags: nil,
   182  		},
   183  		{
   184  			Name: "relative file with comments",
   185  			Args: []string{filepath.Join("tmp", "list.ini")},
   186  			Want: []string{
   187  				"https://example.com",
   188  				"https://more.com?foo=bar",
   189  			},
   190  			WantDiags: nil,
   191  		},
   192  		{
   193  			Name: "one url",
   194  			Args: []string{"https://example.com"},
   195  			Want: []string{
   196  				"https://example.com",
   197  			},
   198  			WantDiags: nil,
   199  		},
   200  		{
   201  			Name: "multiple urls",
   202  			Args: []string{"https://example.com", "http://aws.com"},
   203  			Want: []string{
   204  				"https://example.com",
   205  				"http://aws.com",
   206  			},
   207  			WantDiags: nil,
   208  		},
   209  		{
   210  			Name: "invalid url",
   211  			Args: []string{"no-scheme.org", "https://aws.com"},
   212  			Want: []string{},
   213  			WantDiags: hcl.Diagnostics{
   214  				&hcl.Diagnostic{
   215  					Severity: hcl.DiagError,
   216  					Summary:  "Invalid argument",
   217  					Detail:   "The argument 'no-scheme.org' is not a valid url, nor a file.",
   218  				},
   219  			},
   220  		},
   221  		{
   222  			Name: "file does not exist",
   223  			Args: []string{"file_does_not_exist.txt"},
   224  			Want: []string{},
   225  			WantDiags: hcl.Diagnostics{
   226  				&hcl.Diagnostic{
   227  					Severity: hcl.DiagError,
   228  					Summary:  "Invalid argument",
   229  					Detail:   "The argument 'file_does_not_exist.txt' is not a valid url, nor a file.",
   230  				},
   231  			},
   232  		},
   233  		{
   234  			Name: "file not readable",
   235  			Args: []string{"restricted__r.txt"},
   236  			Want: []string{},
   237  			WantDiags: hcl.Diagnostics{
   238  				&hcl.Diagnostic{
   239  					Severity: hcl.DiagError,
   240  					Summary:  "Could not read file",
   241  					Detail:   "Could not read file '" + filepath.Join(root, "restricted__r.txt") + "'.",
   242  				},
   243  			},
   244  		},
   245  		{
   246  			Name: "url and relative file",
   247  			Args: []string{"https://aws.com", filepath.Join("tmp", "list.ini")},
   248  			Want: []string{
   249  				"https://aws.com",
   250  				"https://example.com",
   251  				"https://more.com?foo=bar",
   252  			},
   253  			WantDiags: nil,
   254  		},
   255  		{
   256  			Name: "url and invalid url in file",
   257  			Args: []string{"https://aws.com", filepath.Join("tmp", "invalid.ini")},
   258  			Want: []string{},
   259  			WantDiags: hcl.Diagnostics{
   260  				&hcl.Diagnostic{
   261  					Severity: hcl.DiagError,
   262  					Summary:  "Invalid URL",
   263  					Detail:   "The string '\\x000' is not a valid url.",
   264  					Subject: &hcl.Range{
   265  						Filename: filepath.Join(root, "tmp", "invalid.ini"),
   266  						Start:    hcl.Pos{Line: 2, Column: 1},
   267  						End:      hcl.Pos{Line: 2, Column: len("\\x000") + 1},
   268  					},
   269  				},
   270  			},
   271  		},
   272  	}
   273  
   274  	for _, test := range tests {
   275  		t.Run(test.Name, func(tc *testing.T) {
   276  			Wd = filepath.Join(root)
   277  
   278  			got, diags := GetURLsFromArgs(test.Args)
   279  
   280  			if !slices.Equal(got, test.Want) {
   281  				tc.Errorf("got: %v, want: %v", got, test.Want)
   282  			}
   283  
   284  			if !reflect.DeepEqual(diags, test.WantDiags) {
   285  				tc.Errorf("got: %v, want: %v", diags, test.WantDiags)
   286  			}
   287  		})
   288  	}
   289  }