github.com/grpc-ecosystem/grpc-gateway/v2@v2.19.1/runtime/marshaler_registry_test.go (about)

     1  package runtime_test
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"net/http"
     9  	"testing"
    10  
    11  	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
    12  )
    13  
    14  func TestMarshalerForRequest(t *testing.T) {
    15  	ctx := context.Background()
    16  	r, err := http.NewRequestWithContext(ctx, "GET", "http://example.com", nil)
    17  	if err != nil {
    18  		t.Fatalf(`http.NewRequest("GET", "http://example.com", nil) failed with %v; want success`, err)
    19  	}
    20  
    21  	mux := runtime.NewServeMux()
    22  
    23  	r.Header.Set("Accept", "application/x-out")
    24  	r.Header.Set("Content-Type", "application/x-in")
    25  	in, out := runtime.MarshalerForRequest(mux, r)
    26  	if _, ok := in.(*runtime.HTTPBodyMarshaler); !ok {
    27  		t.Errorf("in = %#v; want a runtime.HTTPBodyMarshaler", in)
    28  	}
    29  	if _, ok := out.(*runtime.HTTPBodyMarshaler); !ok {
    30  		t.Errorf("out = %#v; want a runtime.HTTPBodyMarshaler", in)
    31  	}
    32  
    33  	marshalers := []dummyMarshaler{0, 1, 2}
    34  	specs := []struct {
    35  		opt runtime.ServeMuxOption
    36  
    37  		wantIn  runtime.Marshaler
    38  		wantOut runtime.Marshaler
    39  	}{
    40  		// The option with wildcard overwrites the default configuration
    41  		{
    42  			opt:     runtime.WithMarshalerOption(runtime.MIMEWildcard, &marshalers[0]),
    43  			wantIn:  &marshalers[0],
    44  			wantOut: &marshalers[0],
    45  		},
    46  		// You can specify a marshaler for a specific MIME type.
    47  		// The output marshaler follows the input one unless specified.
    48  		{
    49  			opt:     runtime.WithMarshalerOption("application/x-in", &marshalers[1]),
    50  			wantIn:  &marshalers[1],
    51  			wantOut: &marshalers[1],
    52  		},
    53  		// You can also separately specify an output marshaler
    54  		{
    55  			opt:     runtime.WithMarshalerOption("application/x-out", &marshalers[2]),
    56  			wantIn:  &marshalers[1],
    57  			wantOut: &marshalers[2],
    58  		},
    59  	}
    60  	for i, spec := range specs {
    61  		var opts []runtime.ServeMuxOption
    62  		for _, s := range specs[:i+1] {
    63  			opts = append(opts, s.opt)
    64  		}
    65  		mux = runtime.NewServeMux(opts...)
    66  
    67  		in, out = runtime.MarshalerForRequest(mux, r)
    68  		if got, want := in, spec.wantIn; got != want {
    69  			t.Errorf("in = %#v; want %#v", got, want)
    70  		}
    71  		if got, want := out, spec.wantOut; got != want {
    72  			t.Errorf("out = %#v; want %#v", got, want)
    73  		}
    74  	}
    75  
    76  	r.Header.Set("Content-Type", "application/x-in; charset=UTF-8")
    77  	in, out = runtime.MarshalerForRequest(mux, r)
    78  	if got, want := in, &marshalers[1]; got != want {
    79  		t.Errorf("in = %#v; want %#v", got, want)
    80  	}
    81  	if got, want := out, &marshalers[2]; got != want {
    82  		t.Errorf("out = %#v; want %#v", got, want)
    83  	}
    84  
    85  	r.Header.Set("Content-Type", "application/x-another")
    86  	r.Header.Set("Accept", "application/x-another")
    87  	in, out = runtime.MarshalerForRequest(mux, r)
    88  	if got, want := in, &marshalers[0]; got != want {
    89  		t.Errorf("in = %#v; want %#v", got, want)
    90  	}
    91  	if got, want := out, &marshalers[0]; got != want {
    92  		t.Errorf("out = %#v; want %#v", got, want)
    93  	}
    94  }
    95  
    96  type dummyMarshaler int
    97  
    98  func (dummyMarshaler) ContentType(_ interface{}) string { return "" }
    99  func (dummyMarshaler) Marshal(interface{}) ([]byte, error) {
   100  	return nil, errors.New("not implemented")
   101  }
   102  
   103  func (dummyMarshaler) Unmarshal([]byte, interface{}) error {
   104  	return errors.New("not implemented")
   105  }
   106  
   107  func (dummyMarshaler) NewDecoder(r io.Reader) runtime.Decoder {
   108  	return dummyDecoder{}
   109  }
   110  func (dummyMarshaler) NewEncoder(w io.Writer) runtime.Encoder {
   111  	return dummyEncoder{}
   112  }
   113  
   114  func (m dummyMarshaler) GoString() string {
   115  	return fmt.Sprintf("dummyMarshaler(%d)", m)
   116  }
   117  
   118  type dummyDecoder struct{}
   119  
   120  func (dummyDecoder) Decode(interface{}) error {
   121  	return errors.New("not implemented")
   122  }
   123  
   124  type dummyEncoder struct{}
   125  
   126  func (dummyEncoder) Encode(interface{}) error {
   127  	return errors.New("not implemented")
   128  }