...

Source file src/github.com/lestrrat-go/jwx/jwx_test.go

Documentation: github.com/lestrrat-go/jwx

     1  package jwx_test
     2  
     3  import (
     4  	"context"
     5  	"crypto/ecdsa"
     6  	"crypto/rsa"
     7  	"fmt"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/lestrrat-go/jwx"
    12  	"github.com/lestrrat-go/jwx/internal/ecutil"
    13  	"github.com/lestrrat-go/jwx/internal/jose"
    14  	"github.com/lestrrat-go/jwx/internal/json"
    15  	"github.com/lestrrat-go/jwx/internal/jwxtest"
    16  	"github.com/lestrrat-go/jwx/jwa"
    17  	"github.com/lestrrat-go/jwx/jwe"
    18  	"github.com/lestrrat-go/jwx/jwk"
    19  	"github.com/stretchr/testify/assert"
    20  )
    21  
    22  func TestShowBuildInfo(t *testing.T) {
    23  	t.Logf("Running tests using JSON backend => %s\n", json.Engine())
    24  	t.Logf("Available elliptic curves:")
    25  	for _, alg := range ecutil.AvailableAlgorithms() {
    26  		t.Logf("  %s", alg)
    27  	}
    28  }
    29  
    30  type jsonUnmarshalWrapper struct {
    31  	buf []byte
    32  }
    33  
    34  func (w jsonUnmarshalWrapper) Decode(v interface{}) error {
    35  	return json.Unmarshal(w.buf, v)
    36  }
    37  
    38  func TestDecoderSetting(t *testing.T) {
    39  	// DO NOT MAKE THIS TEST PARALLEL. This test uses features with global side effects
    40  	const src = `{"foo": 1}`
    41  	for _, useNumber := range []bool{true, false} {
    42  		useNumber := useNumber
    43  		t.Run(fmt.Sprintf("jwx.WithUseNumber(%t)", useNumber), func(t *testing.T) {
    44  			if useNumber {
    45  				jwx.DecoderSettings(jwx.WithUseNumber(useNumber))
    46  				t.Cleanup(func() {
    47  					jwx.DecoderSettings(jwx.WithUseNumber(false))
    48  				})
    49  			}
    50  
    51  			// json.NewDecoder must be called AFTER the above jwx.DecoderSettings call
    52  			decoders := []struct {
    53  				Name    string
    54  				Decoder interface{ Decode(interface{}) error }
    55  			}{
    56  				{Name: "Decoder", Decoder: json.NewDecoder(strings.NewReader(src))},
    57  				{Name: "Unmarshal", Decoder: jsonUnmarshalWrapper{buf: []byte(src)}},
    58  			}
    59  
    60  			for _, tc := range decoders {
    61  				tc := tc
    62  				t.Run(tc.Name, func(t *testing.T) {
    63  					var m map[string]interface{}
    64  					if !assert.NoError(t, tc.Decoder.Decode(&m), `Decode should succeed`) {
    65  						return
    66  					}
    67  
    68  					v, ok := m["foo"]
    69  					if !assert.True(t, ok, `m["foo"] should exist`) {
    70  						return
    71  					}
    72  
    73  					if useNumber {
    74  						if !assert.Equal(t, json.Number("1"), v, `v should be a json.Number object`) {
    75  							return
    76  						}
    77  					} else {
    78  						if !assert.Equal(t, float64(1), v, `v should be a float64`) {
    79  							return
    80  						}
    81  					}
    82  				})
    83  			}
    84  		})
    85  	}
    86  }
    87  
    88  // Test compatibility against `jose` tool
    89  func TestJoseCompatibility(t *testing.T) {
    90  	t.Parallel()
    91  
    92  	if testing.Short() {
    93  		t.Logf("Skipped during short tests")
    94  		return
    95  	}
    96  
    97  	if !jose.Available() {
    98  		t.Logf("`jose` binary not available, skipping tests")
    99  		return
   100  	}
   101  
   102  	t.Run("jwk", func(t *testing.T) {
   103  		t.Parallel()
   104  		testcases := []struct {
   105  			Name      string
   106  			Raw       interface{}
   107  			Template  string
   108  			VerifyKey func(context.Context, *testing.T, jwk.Key) bool
   109  		}{
   110  			{
   111  				Name:     "RSA Private Key (256)",
   112  				Raw:      rsa.PrivateKey{},
   113  				Template: `{"alg": "RS256"}`,
   114  			},
   115  			{
   116  				Name:     "RSA Private Key (384)",
   117  				Raw:      rsa.PrivateKey{},
   118  				Template: `{"alg": "RS384"}`,
   119  			},
   120  			{
   121  				Name:     "RSA Private Key (512)",
   122  				Raw:      rsa.PrivateKey{},
   123  				Template: `{"alg": "RS512"}`,
   124  			},
   125  			{
   126  				Name:     "RSA Private Key with Private Parameters",
   127  				Raw:      rsa.PrivateKey{},
   128  				Template: `{"alg": "RS256", "x-jwx": 1234}`,
   129  				VerifyKey: func(ctx context.Context, t *testing.T, key jwk.Key) bool {
   130  					m, err := key.AsMap(ctx)
   131  					if !assert.NoError(t, err, `key.AsMap() should succeed`) {
   132  						return false
   133  					}
   134  
   135  					if !assert.Equal(t, float64(1234), m["x-jwx"], `private parameters should match`) {
   136  						return false
   137  					}
   138  
   139  					return true
   140  				},
   141  			},
   142  		}
   143  
   144  		for _, tc := range testcases {
   145  			tc := tc
   146  			t.Run(tc.Name, func(t *testing.T) {
   147  				t.Parallel()
   148  
   149  				ctx, cancel := context.WithCancel(context.Background())
   150  				defer cancel()
   151  
   152  				keyfile, cleanup, err := jose.GenerateJwk(ctx, t, tc.Template)
   153  				if !assert.NoError(t, err, `jose.GenerateJwk should succeed`) {
   154  					return
   155  				}
   156  				defer cleanup()
   157  
   158  				webkey, err := jwxtest.ParseJwkFile(ctx, keyfile)
   159  				if !assert.NoError(t, err, `ParseJwkFile should succeed`) {
   160  					return
   161  				}
   162  
   163  				if vk := tc.VerifyKey; vk != nil {
   164  					if !vk(ctx, t, webkey) {
   165  						return
   166  					}
   167  				}
   168  
   169  				if !assert.NoError(t, webkey.Raw(&tc.Raw), `jwk.Raw should succeed`) {
   170  					return
   171  				}
   172  			})
   173  		}
   174  	})
   175  	t.Run("jwe", func(t *testing.T) {
   176  		t.Parallel()
   177  		tests := []interopTest{
   178  			{jwa.RSA1_5, jwa.A128GCM},
   179  			{jwa.RSA1_5, jwa.A128CBC_HS256},
   180  			{jwa.RSA1_5, jwa.A256CBC_HS512},
   181  			{jwa.RSA_OAEP, jwa.A128GCM},
   182  			{jwa.RSA_OAEP, jwa.A128CBC_HS256},
   183  			{jwa.RSA_OAEP, jwa.A256CBC_HS512},
   184  			{jwa.RSA_OAEP_256, jwa.A128GCM},
   185  			{jwa.RSA_OAEP_256, jwa.A128CBC_HS256},
   186  			{jwa.RSA_OAEP_256, jwa.A256CBC_HS512},
   187  			{jwa.ECDH_ES, jwa.A128GCM},
   188  			{jwa.ECDH_ES, jwa.A256GCM},
   189  			{jwa.ECDH_ES, jwa.A128CBC_HS256},
   190  			{jwa.ECDH_ES, jwa.A256CBC_HS512},
   191  			{jwa.ECDH_ES_A128KW, jwa.A128GCM},
   192  			{jwa.ECDH_ES_A128KW, jwa.A128CBC_HS256},
   193  			{jwa.ECDH_ES_A256KW, jwa.A256GCM},
   194  			{jwa.ECDH_ES_A256KW, jwa.A256CBC_HS512},
   195  			{jwa.A128KW, jwa.A128GCM},
   196  			{jwa.A128KW, jwa.A128CBC_HS256},
   197  			{jwa.A256KW, jwa.A256GCM},
   198  			{jwa.A256KW, jwa.A256CBC_HS512},
   199  			{jwa.A128GCMKW, jwa.A128GCM},
   200  			{jwa.A128GCMKW, jwa.A128CBC_HS256},
   201  			{jwa.A256GCMKW, jwa.A256GCM},
   202  			{jwa.A256GCMKW, jwa.A256CBC_HS512},
   203  			{jwa.PBES2_HS256_A128KW, jwa.A128GCM},
   204  			{jwa.PBES2_HS256_A128KW, jwa.A128CBC_HS256},
   205  			{jwa.PBES2_HS384_A192KW, jwa.A192GCM},
   206  			{jwa.PBES2_HS384_A192KW, jwa.A192CBC_HS384},
   207  			{jwa.PBES2_HS512_A256KW, jwa.A256GCM},
   208  			{jwa.PBES2_HS512_A256KW, jwa.A256CBC_HS512},
   209  			{jwa.DIRECT, jwa.A128GCM},
   210  			{jwa.DIRECT, jwa.A128CBC_HS256},
   211  			{jwa.DIRECT, jwa.A256GCM},
   212  			{jwa.DIRECT, jwa.A256CBC_HS512},
   213  		}
   214  
   215  		for _, test := range tests {
   216  			test := test
   217  			t.Run(fmt.Sprintf("%s-%s", test.alg, test.enc), func(t *testing.T) {
   218  				t.Parallel()
   219  				ctx, cancel := context.WithCancel(context.Background())
   220  				defer cancel()
   221  				joseInteropTest(ctx, test, t)
   222  			})
   223  		}
   224  	})
   225  	t.Run("jws", func(t *testing.T) {
   226  		t.Parallel()
   227  		tests := []jwa.SignatureAlgorithm{
   228  			jwa.ES256,
   229  			//jwa.ES256K,
   230  			jwa.ES384,
   231  			jwa.ES512,
   232  			//jwa.EdDSA,
   233  			jwa.HS256,
   234  			jwa.HS384,
   235  			jwa.HS512,
   236  			jwa.PS256,
   237  			jwa.PS384,
   238  			jwa.PS512,
   239  			jwa.RS256,
   240  			jwa.RS384,
   241  			jwa.RS512,
   242  		}
   243  		for _, test := range tests {
   244  			test := test
   245  			t.Run(test.String(), func(t *testing.T) {
   246  				t.Parallel()
   247  				ctx, cancel := context.WithCancel(context.Background())
   248  				defer cancel()
   249  				joseJwsInteropTest(ctx, test, t)
   250  			})
   251  		}
   252  	})
   253  }
   254  
   255  type interopTest struct {
   256  	alg jwa.KeyEncryptionAlgorithm
   257  	enc jwa.ContentEncryptionAlgorithm
   258  }
   259  
   260  func joseInteropTest(ctx context.Context, spec interopTest, t *testing.T) {
   261  	t.Helper()
   262  
   263  	expected := []byte("Lorem ipsum")
   264  
   265  	// let jose generate a key file
   266  	alg := spec.alg.String()
   267  	if spec.alg == jwa.DIRECT {
   268  		alg = spec.enc.String()
   269  	}
   270  	joseJwkFile, joseJwkCleanup, err := jose.GenerateJwk(ctx, t, fmt.Sprintf(`{"alg": "%s"}`, alg))
   271  	if !assert.NoError(t, err, `jose.GenerateJwk should succeed`) {
   272  		return
   273  	}
   274  	defer joseJwkCleanup()
   275  
   276  	// Load the JWK generated by jose
   277  	jwxJwk, err := jwxtest.ParseJwkFile(ctx, joseJwkFile)
   278  	if !assert.NoError(t, err, `jwxtest.ParseJwkFile should succeed`) {
   279  		return
   280  	}
   281  
   282  	t.Run("Parse JWK via jwx", func(t *testing.T) {
   283  		switch spec.alg {
   284  		case jwa.RSA1_5, jwa.RSA_OAEP, jwa.RSA_OAEP_256:
   285  			var rawkey rsa.PrivateKey
   286  			if !assert.NoError(t, jwxJwk.Raw(&rawkey), `jwk.Raw should succeed`) {
   287  				return
   288  			}
   289  		case jwa.ECDH_ES, jwa.ECDH_ES_A128KW, jwa.ECDH_ES_A192KW, jwa.ECDH_ES_A256KW:
   290  			var rawkey ecdsa.PrivateKey
   291  			if !assert.NoError(t, jwxJwk.Raw(&rawkey), `jwk.Raw should succeed`) {
   292  				return
   293  			}
   294  		default:
   295  			var rawkey []byte
   296  			if !assert.NoError(t, jwxJwk.Raw(&rawkey), `jwk.Raw should succeed`) {
   297  				return
   298  			}
   299  		}
   300  	})
   301  	t.Run("Encrypt with jose, Decrypt with jwx", func(t *testing.T) {
   302  		// let jose encrypt payload using the key file
   303  		joseCryptFile, joseCryptCleanup, err := jose.EncryptJwe(ctx, t, expected, spec.alg.String(), joseJwkFile, spec.enc.String(), true)
   304  		if !assert.NoError(t, err, `jose.EncryptJwe should succeed`) {
   305  			return
   306  		}
   307  		defer joseCryptCleanup()
   308  
   309  		jwxtest.DumpFile(t, joseCryptFile)
   310  
   311  		// let jwx decrypt the jose crypted file
   312  		payload, err := jwxtest.DecryptJweFile(ctx, joseCryptFile, spec.alg, joseJwkFile)
   313  		if !assert.NoError(t, err, `decryptFile.DecryptJwe should succeed`) {
   314  			return
   315  		}
   316  
   317  		if !assert.Equal(t, expected, payload, `decrypted payloads should match`) {
   318  			return
   319  		}
   320  	})
   321  	t.Run("Encrypt with jwx, Decrypt with jose", func(t *testing.T) {
   322  		jwxCryptFile, jwxCryptCleanup, err := jwxtest.EncryptJweFile(ctx, expected, spec.alg, joseJwkFile, spec.enc, jwa.NoCompress)
   323  		if !assert.NoError(t, err, `jwxtest.EncryptJweFile should succeed`) {
   324  			return
   325  		}
   326  		defer jwxCryptCleanup()
   327  
   328  		payload, err := jose.DecryptJwe(ctx, t, jwxCryptFile, joseJwkFile)
   329  		if !assert.NoError(t, err, `jose.DecryptJwe should succeed`) {
   330  			return
   331  		}
   332  
   333  		if !assert.Equal(t, expected, payload, `decrypted payloads should match`) {
   334  			return
   335  		}
   336  	})
   337  }
   338  
   339  func joseJwsInteropTest(ctx context.Context, alg jwa.SignatureAlgorithm, t *testing.T) {
   340  	t.Helper()
   341  
   342  	expected := []byte(`{"foo":"bar"}`)
   343  
   344  	joseJwkFile, joseJwkCleanup, err := jose.GenerateJwk(ctx, t, fmt.Sprintf(`{"alg": "%s"}`, alg))
   345  	if !assert.NoError(t, err, `jose.GenerateJwk should succeed`) {
   346  		return
   347  	}
   348  	defer joseJwkCleanup()
   349  
   350  	// Load the JWK generated by jose
   351  	_, err = jwxtest.ParseJwkFile(ctx, joseJwkFile)
   352  	if !assert.NoError(t, err, `jwxtest.ParseJwkFile should succeed`) {
   353  		return
   354  	}
   355  	t.Run("Sign with jose, Verify with jwx", func(t *testing.T) {
   356  		// let jose encrypt payload using the key file
   357  		joseCryptFile, joseCryptCleanup, err := jose.SignJws(ctx, t, expected, joseJwkFile, true)
   358  		if !assert.NoError(t, err, `jose.SignJws should succeed`) {
   359  			return
   360  		}
   361  		defer joseCryptCleanup()
   362  
   363  		jwxtest.DumpFile(t, joseCryptFile)
   364  
   365  		// let jwx decrypt the jose crypted file
   366  		payload, err := jwxtest.VerifyJwsFile(ctx, joseCryptFile, alg, joseJwkFile)
   367  		if !assert.NoError(t, err, `jwxtest.VerifyJwsFile should succeed`) {
   368  			return
   369  		}
   370  
   371  		if !assert.Equal(t, expected, payload, `decrypted payloads should match`) {
   372  			return
   373  		}
   374  	})
   375  	t.Run("Sign with jwx, Verify with jose", func(t *testing.T) {
   376  		jwxCryptFile, jwxCryptCleanup, err := jwxtest.SignJwsFile(ctx, expected, alg, joseJwkFile)
   377  		if !assert.NoError(t, err, `jwxtest.SignJwsFile should succeed`) {
   378  			return
   379  		}
   380  		defer jwxCryptCleanup()
   381  
   382  		payload, err := jose.VerifyJws(ctx, t, jwxCryptFile, joseJwkFile)
   383  		if !assert.NoError(t, err, `jose.VerifyJws should succeed`) {
   384  			return
   385  		}
   386  
   387  		if !assert.Equal(t, expected, payload, `decrypted payloads should match`) {
   388  			return
   389  		}
   390  	})
   391  }
   392  
   393  func TestGHIssue230(t *testing.T) {
   394  	t.Parallel()
   395  	if !jose.Available() {
   396  		t.SkipNow()
   397  	}
   398  
   399  	data := "eyJhbGciOiJFQ0RILUVTIiwiY2xldmlzIjp7InBpbiI6InRhbmciLCJ0YW5nIjp7ImFkdiI6eyJrZXlzIjpbeyJhbGciOiJFQ01SIiwiY3J2IjoiUC01MjEiLCJrZXlfb3BzIjpbImRlcml2ZUtleSJdLCJrdHkiOiJFQyIsIngiOiJBZm5tR2xHRTFHRUZ5NEpUT2tGWmo5ZEhEUmdpVE5IeFBST3hpZDZLdm0xVGRFQkZ3bElsSVB6TG5lTjlnb3h6OUVGYmJLM3BoN0tWZS05aVF4MmxhOVNFIiwieSI6IkFmZGFaTVYzVzk1NE14elQxeXF3MWVaRU9xTFFZZnBXSGczMlJvekhyQjBEYmoxWWV3OVFvTDg1M2Y2aUw2REIyRC1nbEcxSFFsb3czdGRNdFhjN1pSY0IifSx7ImFsZyI6IkVTNTEyIiwiY3J2IjoiUC01MjEiLCJrZXlfb3BzIjpbInZlcmlmeSJdLCJrdHkiOiJFQyIsIngiOiJBR0drcXRPZzZqel9pZnhmVnVWQ01CalVySFhCTGtfS2hIb3lKRkU5NmJucTZKZVVHNFNMZnRrZ2FIYk5WT0U4Q3Mwd0JqR0ZkSWxDbnBmak94RGJfbFBoIiwieSI6IkFLU0laT0JYY1Jfa3RkWjZ6T3F3TGI5SEJzai0yYmRMUmw5dFZVbnVlV2N3aXg5X3NiekliSWx0SE9YUGhBTW9yaUlYMWVyNzc4Unh6Vkg5d0FtaUhGa1kifV19LCJ1cmwiOiJodHRwOi8vbG9jYWxob3N0OjM5NDIxIn19LCJlbmMiOiJBMjU2R0NNIiwiZXBrIjp7ImNydiI6IlAtNTIxIiwia3R5IjoiRUMiLCJ4IjoiQUJMUm9sQWotZFdVdzZLSjg2T3J6d1F6RjlGT09URFZBZnNWNkh0OU0zREhyQ045Q0N6dVJ1b3cwbWp6M3BjZnVCaFpYREpfN0dkdzE0LXdneV9fTFNrYyIsInkiOiJBT3NRMzlKZmFQVGhjc2FZTjhSMVBHXzIwYXZxRU1NRl9fM2RHQmI3c1BqNmktNEJORDVMdkZ3cVpJT1l4SS1kVWlvNzkyOWY1YnE0eEdJY0lGWWtlbllxIn0sImtpZCI6ImhlZmVpNzVqMkp4Sko3REZnSDAxUWlOVmlGayJ9..GH3-8v7wfxEsRnki.wns--EIYTRjM3Tb0HyA.EGn2Gq7PnSVvPaMN0oRi5A"
   400  
   401  	compactMsg, err := jwe.ParseString(data)
   402  	if !assert.NoError(t, err, `jwe.ParseString should succeed`) {
   403  		return
   404  	}
   405  
   406  	formatted, err := jose.FmtJwe(context.TODO(), t, []byte(data))
   407  	if !assert.NoError(t, err, `jose.FmtJwe should succeed`) {
   408  		return
   409  	}
   410  
   411  	jsonMsg, err := jwe.Parse(formatted)
   412  	if !assert.NoError(t, err, `jwe.Parse should succeed`) {
   413  		return
   414  	}
   415  
   416  	if !assert.Equal(t, compactMsg, jsonMsg, `messages should match`) {
   417  		return
   418  	}
   419  }
   420  
   421  func TestGuessFormat(t *testing.T) {
   422  	testcases := []struct {
   423  		Name     string
   424  		Expected jwx.FormatKind
   425  		Source   []byte
   426  	}{
   427  		{
   428  			Name:     "Raw String",
   429  			Expected: jwx.UnknownFormat,
   430  			Source:   []byte(`Hello, World`),
   431  		},
   432  		{
   433  			Name:     "Random JSON Object",
   434  			Expected: jwx.UnknownFormat,
   435  			Source:   []byte(`{"random": "JSON"}`),
   436  		},
   437  		{
   438  			Name:     "Random JSON Array",
   439  			Expected: jwx.UnknownFormat,
   440  			Source:   []byte(`["random", "JSON"]`),
   441  		},
   442  		{
   443  			Name:     "Random Broken JSON",
   444  			Expected: jwx.UnknownFormat,
   445  			Source:   []byte(`{"aud": "foo", "x-customg": "extra semicolon after this string", }`),
   446  		},
   447  		{
   448  			Name:     "JWS",
   449  			Expected: jwx.JWS,
   450  			// from  https://tools.ietf.org/html/rfc7515#appendix-A.1
   451  			Source: []byte(`eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk`),
   452  		},
   453  		{
   454  			Name:     "JWE",
   455  			Expected: jwx.JWE,
   456  			Source:   []byte(`eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGeipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDbSv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaVmqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je81860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi6UklfCpIMfIjf7iGdXKHzg.48V1_ALb6US04U3b.5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6jiSdiwkIr3ajwQzaBtQD_A.XFBoMYUZodetZdvTiFvSkQ`),
   457  		},
   458  		{
   459  			Name:     "JWK",
   460  			Expected: jwx.JWK,
   461  			Source:   []byte(`{"kty":"OKP","crv":"X25519","x":"3p7bfXt9wbTTW2HC7OQ1Nz-DQ8hbeGdNrfx-FG-IK08"}`),
   462  		},
   463  		{
   464  			Name:     "JWKS",
   465  			Expected: jwx.JWKS,
   466  			Source:   []byte(`{"keys":[{"kty":"OKP","crv":"X25519","x":"3p7bfXt9wbTTW2HC7OQ1Nz-DQ8hbeGdNrfx-FG-IK08"}]}`),
   467  		},
   468  		{
   469  			Name:     "JWS (JSON)",
   470  			Expected: jwx.JWS,
   471  			Source:   []byte(`{"signatures": [], "payload": ""}`),
   472  		},
   473  		{
   474  			Name:     "JWT",
   475  			Expected: jwx.JWT,
   476  			Source:   []byte(`{"aud":"github.com/lestrrat-go/jwx"}`),
   477  		},
   478  	}
   479  
   480  	for _, tc := range testcases {
   481  		tc := tc
   482  		t.Run(tc.Name, func(t *testing.T) {
   483  			got := jwx.GuessFormat(tc.Source)
   484  			if !assert.Equal(t, got, tc.Expected, `value of jwx.GuessFormat should match (%s != %s)`, got, tc.Expected) {
   485  				return
   486  			}
   487  		})
   488  	}
   489  }
   490  
   491  func TestFormat(t *testing.T) {
   492  	testcases := []struct {
   493  		Value    jwx.FormatKind
   494  		Expected string
   495  		Error    bool
   496  	}{
   497  		{
   498  			Value:    jwx.UnknownFormat,
   499  			Expected: "UnknownFormat",
   500  		},
   501  		{
   502  			Value:    jwx.JWE,
   503  			Expected: "JWE",
   504  		},
   505  		{
   506  			Value:    jwx.JWS,
   507  			Expected: "JWS",
   508  		},
   509  		{
   510  			Value:    jwx.JWK,
   511  			Expected: "JWK",
   512  		},
   513  		{
   514  			Value:    jwx.JWKS,
   515  			Expected: "JWKS",
   516  		},
   517  		{
   518  			Value:    jwx.JWT,
   519  			Expected: "JWT",
   520  		},
   521  		{
   522  			Value:    jwx.FormatKind(9999999),
   523  			Expected: "FormatKind(9999999)",
   524  		},
   525  	}
   526  	for _, tc := range testcases {
   527  		tc := tc
   528  		t.Run(tc.Expected, func(t *testing.T) {
   529  			if !assert.Equal(t, tc.Expected, tc.Value.String(), `stringification should match`) {
   530  				return
   531  			}
   532  		})
   533  	}
   534  }
   535  

View as plain text