github.com/erda-project/erda-infra@v1.0.10-0.20240327085753-f3a249292aeb/pkg/transport/http/httprule/parse_test.go (about)

     1  // Copyright (c) 2021 Terminus, Inc.
     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  
    15  // Reference: https://github.com/grpc-ecosystem/grpc-gateway/blob/v2.3.0/internal/httprule/parse_test.go
    16  
    17  package httprule
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"testing"
    23  )
    24  
    25  func TestTokenize(t *testing.T) {
    26  	for _, spec := range []struct {
    27  		src    string
    28  		tokens []string
    29  		verb   string
    30  	}{
    31  		{
    32  			src:    "",
    33  			tokens: []string{eof},
    34  		},
    35  		{
    36  			src:    "v1",
    37  			tokens: []string{"v1", eof},
    38  		},
    39  		{
    40  			src:    "v1/b",
    41  			tokens: []string{"v1", "/", "b", eof},
    42  		},
    43  		{
    44  			src:    "v1/endpoint/*",
    45  			tokens: []string{"v1", "/", "endpoint", "/", "*", eof},
    46  		},
    47  		{
    48  			src:    "v1/endpoint/**",
    49  			tokens: []string{"v1", "/", "endpoint", "/", "**", eof},
    50  		},
    51  		{
    52  			src: "v1/b/{bucket_name=*}",
    53  			tokens: []string{
    54  				"v1", "/",
    55  				"b", "/",
    56  				"{", "bucket_name", "=", "*", "}",
    57  				eof,
    58  			},
    59  		},
    60  		{
    61  			src: "v1/b/{bucket_name=buckets/*}",
    62  			tokens: []string{
    63  				"v1", "/",
    64  				"b", "/",
    65  				"{", "bucket_name", "=", "buckets", "/", "*", "}",
    66  				eof,
    67  			},
    68  		},
    69  		{
    70  			src: "v1/b/{bucket_name=buckets/*}/o",
    71  			tokens: []string{
    72  				"v1", "/",
    73  				"b", "/",
    74  				"{", "bucket_name", "=", "buckets", "/", "*", "}", "/",
    75  				"o",
    76  				eof,
    77  			},
    78  		},
    79  		{
    80  			src: "v1/b/{bucket_name=buckets/*}/o/{name}",
    81  			tokens: []string{
    82  				"v1", "/",
    83  				"b", "/",
    84  				"{", "bucket_name", "=", "buckets", "/", "*", "}", "/",
    85  				"o", "/", "{", "name", "}",
    86  				eof,
    87  			},
    88  		},
    89  		{
    90  			src: "v1/a=b&c=d;e=f:g/endpoint.rdf",
    91  			tokens: []string{
    92  				"v1", "/",
    93  				"a=b&c=d;e=f:g", "/",
    94  				"endpoint.rdf",
    95  				eof,
    96  			},
    97  		},
    98  		{
    99  			src: "v1/a/{endpoint}:a",
   100  			tokens: []string{
   101  				"v1", "/",
   102  				"a", "/",
   103  				"{", "endpoint", "}",
   104  				eof,
   105  			},
   106  			verb: "a",
   107  		},
   108  		{
   109  			src: "v1/a/{endpoint}:b:c",
   110  			tokens: []string{
   111  				"v1", "/",
   112  				"a", "/",
   113  				"{", "endpoint", "}",
   114  				eof,
   115  			},
   116  			verb: "b:c",
   117  		},
   118  	} {
   119  		tokens, verb := tokenize(spec.src)
   120  		if got, want := tokens, spec.tokens; !reflect.DeepEqual(got, want) {
   121  			t.Errorf("tokenize(%q) = %q, _; want %q, _", spec.src, got, want)
   122  		}
   123  
   124  		switch {
   125  		case spec.verb != "":
   126  			if got, want := verb, spec.verb; !reflect.DeepEqual(got, want) {
   127  				t.Errorf("tokenize(%q) = %q, _; want %q, _", spec.src, got, want)
   128  			}
   129  
   130  		default:
   131  			if got, want := verb, ""; got != want {
   132  				t.Errorf("tokenize(%q) = _, %q; want _, %q", spec.src, got, want)
   133  			}
   134  
   135  			src := fmt.Sprintf("%s:%s", spec.src, "LOCK")
   136  			tokens, verb = tokenize(src)
   137  			if got, want := tokens, spec.tokens; !reflect.DeepEqual(got, want) {
   138  				t.Errorf("tokenize(%q) = %q, _; want %q, _", src, got, want)
   139  			}
   140  			if got, want := verb, "LOCK"; got != want {
   141  				t.Errorf("tokenize(%q) = _, %q; want _, %q", src, got, want)
   142  			}
   143  		}
   144  	}
   145  }
   146  
   147  func TestParseSegments(t *testing.T) {
   148  	for _, spec := range []struct {
   149  		tokens []string
   150  		want   []segment
   151  	}{
   152  		{
   153  			tokens: []string{"v1", eof},
   154  			want: []segment{
   155  				literal("v1"),
   156  			},
   157  		},
   158  		{
   159  			tokens: []string{"/", eof},
   160  			want: []segment{
   161  				wildcard{},
   162  			},
   163  		},
   164  		{
   165  			tokens: []string{"-._~!$&'()*+,;=:@", eof},
   166  			want: []segment{
   167  				literal("-._~!$&'()*+,;=:@"),
   168  			},
   169  		},
   170  		{
   171  			tokens: []string{"%e7%ac%ac%e4%b8%80%e7%89%88", eof},
   172  			want: []segment{
   173  				literal("%e7%ac%ac%e4%b8%80%e7%89%88"),
   174  			},
   175  		},
   176  		{
   177  			tokens: []string{"v1", "/", "*", eof},
   178  			want: []segment{
   179  				literal("v1"),
   180  				wildcard{},
   181  			},
   182  		},
   183  		{
   184  			tokens: []string{"v1", "/", "**", eof},
   185  			want: []segment{
   186  				literal("v1"),
   187  				deepWildcard{},
   188  			},
   189  		},
   190  		{
   191  			tokens: []string{"{", "name", "}", eof},
   192  			want: []segment{
   193  				variable{
   194  					path: "name",
   195  					segments: []segment{
   196  						wildcard{},
   197  					},
   198  				},
   199  			},
   200  		},
   201  		{
   202  			tokens: []string{"{", "name", "=", "*", "}", eof},
   203  			want: []segment{
   204  				variable{
   205  					path: "name",
   206  					segments: []segment{
   207  						wildcard{},
   208  					},
   209  				},
   210  			},
   211  		},
   212  		{
   213  			tokens: []string{"{", "field", ".", "nested", ".", "nested2", "=", "*", "}", eof},
   214  			want: []segment{
   215  				variable{
   216  					path: "field.nested.nested2",
   217  					segments: []segment{
   218  						wildcard{},
   219  					},
   220  				},
   221  			},
   222  		},
   223  		{
   224  			tokens: []string{"{", "name", "=", "a", "/", "b", "/", "*", "}", eof},
   225  			want: []segment{
   226  				variable{
   227  					path: "name",
   228  					segments: []segment{
   229  						literal("a"),
   230  						literal("b"),
   231  						wildcard{},
   232  					},
   233  				},
   234  			},
   235  		},
   236  		{
   237  			tokens: []string{
   238  				"v1", "/",
   239  				"{",
   240  				"name", ".", "nested", ".", "nested2",
   241  				"=",
   242  				"a", "/", "b", "/", "*",
   243  				"}", "/",
   244  				"o", "/",
   245  				"{",
   246  				"another_name",
   247  				"=",
   248  				"a", "/", "b", "/", "*", "/", "c",
   249  				"}", "/",
   250  				"**",
   251  				eof,
   252  			},
   253  			want: []segment{
   254  				literal("v1"),
   255  				variable{
   256  					path: "name.nested.nested2",
   257  					segments: []segment{
   258  						literal("a"),
   259  						literal("b"),
   260  						wildcard{},
   261  					},
   262  				},
   263  				literal("o"),
   264  				variable{
   265  					path: "another_name",
   266  					segments: []segment{
   267  						literal("a"),
   268  						literal("b"),
   269  						wildcard{},
   270  						literal("c"),
   271  					},
   272  				},
   273  				deepWildcard{},
   274  			},
   275  		},
   276  	} {
   277  		p := parser{tokens: spec.tokens}
   278  		segs, err := p.topLevelSegments()
   279  		if err != nil {
   280  			t.Errorf("parser{%q}.segments() failed with %v; want success", spec.tokens, err)
   281  			continue
   282  		}
   283  		if got, want := segs, spec.want; !reflect.DeepEqual(got, want) {
   284  			t.Errorf("parser{%q}.segments() = %#v; want %#v", spec.tokens, got, want)
   285  		}
   286  		if got := p.tokens; len(got) > 0 {
   287  			t.Errorf("p.tokens = %q; want []; spec.tokens=%q", got, spec.tokens)
   288  		}
   289  	}
   290  }
   291  
   292  func TestParseSegmentsWithErrors(t *testing.T) {
   293  	for _, spec := range []struct {
   294  		tokens []string
   295  	}{
   296  		{
   297  			// double slash
   298  			tokens: []string{"//", eof},
   299  		},
   300  		{
   301  			// invalid literal
   302  			tokens: []string{"a?b", eof},
   303  		},
   304  		{
   305  			// invalid percent-encoding
   306  			tokens: []string{"%", eof},
   307  		},
   308  		{
   309  			// invalid percent-encoding
   310  			tokens: []string{"%2", eof},
   311  		},
   312  		{
   313  			// invalid percent-encoding
   314  			tokens: []string{"a%2z", eof},
   315  		},
   316  		{
   317  			// empty segments
   318  			tokens: []string{eof},
   319  		},
   320  		{
   321  			// unterminated variable
   322  			tokens: []string{"{", "name", eof},
   323  		},
   324  		{
   325  			// unterminated variable
   326  			tokens: []string{"{", "name", "=", eof},
   327  		},
   328  		{
   329  			// unterminated variable
   330  			tokens: []string{"{", "name", "=", "*", eof},
   331  		},
   332  		{
   333  			// empty component in field path
   334  			tokens: []string{"{", "name", ".", "}", eof},
   335  		},
   336  		{
   337  			// empty component in field path
   338  			tokens: []string{"{", "name", ".", ".", "nested", "}", eof},
   339  		},
   340  		{
   341  			// invalid character in identifier
   342  			tokens: []string{"{", "field-name", "}", eof},
   343  		},
   344  		{
   345  			// no slash between segments
   346  			tokens: []string{"v1", "endpoint", eof},
   347  		},
   348  		{
   349  			// no slash between segments
   350  			tokens: []string{"v1", "{", "name", "}", eof},
   351  		},
   352  	} {
   353  		p := parser{tokens: spec.tokens}
   354  		segs, err := p.topLevelSegments()
   355  		if err == nil {
   356  			t.Errorf("parser{%q}.segments() succeeded; want InvalidTemplateError; accepted %#v", spec.tokens, segs)
   357  			continue
   358  		}
   359  		t.Log(err)
   360  	}
   361  }