...

Source file src/github.com/aws/smithy-go/encoding/xml/xml_decoder_test.go

Documentation: github.com/aws/smithy-go/encoding/xml

     1  package xml
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/xml"
     6  	"io"
     7  	"reflect"
     8  	"strings"
     9  	"testing"
    10  )
    11  
    12  func TestXMLNodeDecoder_Token(t *testing.T) {
    13  	cases := map[string]struct {
    14  		responseBody         io.Reader
    15  		expectedStartElement xml.StartElement
    16  		expectedDone         bool
    17  		expectedError        string
    18  	}{
    19  		"simple success case": {
    20  			responseBody: bytes.NewReader([]byte(`<Response>abc</Response>`)),
    21  			expectedStartElement: xml.StartElement{
    22  				Name: xml.Name{
    23  					Local: "",
    24  				},
    25  			},
    26  			expectedDone: true,
    27  		},
    28  		"no value": {
    29  			responseBody: bytes.NewReader([]byte(`<Response></Response>`)),
    30  			expectedDone: true,
    31  		},
    32  		"empty body": {
    33  			responseBody:  bytes.NewReader([]byte(``)),
    34  			expectedError: "EOF",
    35  		},
    36  		"with indentation": {
    37  			responseBody: bytes.NewReader([]byte(`	<Response><Struct>abc</Struct></Response>`)),
    38  			expectedStartElement: xml.StartElement{
    39  				Name: xml.Name{
    40  					Local: "Struct",
    41  				},
    42  				Attr: []xml.Attr{},
    43  			},
    44  		},
    45  		"with comment and indentation": {
    46  			responseBody: bytes.NewReader([]byte(`<!--comment-->	<Response><Struct>abc</Struct></Response>`)),
    47  			expectedStartElement: xml.StartElement{
    48  				Name: xml.Name{
    49  					Local: "Struct",
    50  				},
    51  				Attr: []xml.Attr{},
    52  			},
    53  		},
    54  		"attr with namespace": {
    55  			responseBody: bytes.NewReader([]byte(`<Response><Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser"></Grantee></Response>`)),
    56  			expectedStartElement: xml.StartElement{
    57  				Name: xml.Name{
    58  					Local: "Grantee",
    59  				},
    60  				Attr: []xml.Attr{
    61  					{
    62  						Name: xml.Name{
    63  							Space: "xmlns",
    64  							Local: "xsi",
    65  						},
    66  						Value: "http://www.w3.org/2001/XMLSchema-instance",
    67  					},
    68  					{
    69  						Name: xml.Name{
    70  							Space: "xsi",
    71  							Local: "type",
    72  						},
    73  						Value: "CanonicalUser",
    74  					},
    75  				},
    76  			},
    77  		},
    78  	}
    79  
    80  	for name, c := range cases {
    81  		t.Run(name, func(t *testing.T) {
    82  			xmlDecoder := xml.NewDecoder(c.responseBody)
    83  			st, err := FetchRootElement(xmlDecoder)
    84  			if err != nil {
    85  				if len(c.expectedError) == 0 {
    86  					t.Fatalf("Expected no error, got %v", err)
    87  				}
    88  
    89  				if e, a := c.expectedError, err; !strings.Contains(err.Error(), c.expectedError) {
    90  					t.Fatalf("expected error to contain %v, found %v", e, a.Error())
    91  				}
    92  			}
    93  			nodeDecoder := WrapNodeDecoder(xmlDecoder, st)
    94  			token, done, err := nodeDecoder.Token()
    95  			if err != nil {
    96  				if len(c.expectedError) == 0 {
    97  					t.Fatalf("Expected no error, got %v", err)
    98  				}
    99  
   100  				if e, a := c.expectedError, err; !strings.Contains(err.Error(), c.expectedError) {
   101  					t.Fatalf("expected error to contain %v, found %v", e, a.Error())
   102  				}
   103  			}
   104  
   105  			if e, a := c.expectedDone, done; e != a {
   106  				t.Fatalf("expected a valid end element token for the xml document, got none")
   107  			}
   108  
   109  			if !reflect.DeepEqual(c.expectedStartElement, token) {
   110  				t.Fatalf("Found diff : %v != %v", c.expectedStartElement, token)
   111  			}
   112  		})
   113  	}
   114  }
   115  
   116  func TestXMLNodeDecoder_TokenExample(t *testing.T) {
   117  	responseBody := bytes.NewReader([]byte(`<Struct><Response>abc</Response></Struct>`))
   118  
   119  	xmlDecoder := xml.NewDecoder(responseBody)
   120  	// Fetches <Struct> tag as start element.
   121  	st, err := FetchRootElement(xmlDecoder)
   122  	if err != nil {
   123  		t.Fatalf("Expected no error, got %v", err)
   124  	}
   125  
   126  	// nodeDecoder will track <Struct> tag as root node of the document
   127  	nodeDecoder := WrapNodeDecoder(xmlDecoder, st)
   128  
   129  	// Retrieves <Response> tag
   130  	token, done, err := nodeDecoder.Token()
   131  	if err != nil {
   132  		t.Fatalf("Expected no error, got %v", err)
   133  
   134  	}
   135  
   136  	expect := xml.StartElement{Name: xml.Name{Local: "Response"}, Attr: []xml.Attr{}}
   137  	if !reflect.DeepEqual(expect, token) {
   138  		t.Fatalf("Found diff : %v != %v", expect, token)
   139  	}
   140  	if done {
   141  		t.Fatalf("expected decoding to not be done yet")
   142  	}
   143  
   144  	// Skips the value and gets </Response> that is the end token of previously retrieved <Response> tag.
   145  	// The way node decoder works it only keeps track of the root start tag using which it was initialized.
   146  	// Here <Struct> is used to initialize, while</Response> is end element corresponding to already read
   147  	// <Response> tag. We won't be done until we receive </Struct>
   148  	token, done, err = nodeDecoder.Token()
   149  	if err != nil {
   150  		t.Fatalf("Expected no error, got %v", err)
   151  
   152  	}
   153  
   154  	expect = xml.StartElement{Name: xml.Name{Local: ""}, Attr: nil}
   155  	if !reflect.DeepEqual(expect, token) {
   156  		t.Fatalf("Found diff : %v != %v", expect, token)
   157  	}
   158  	if done {
   159  		t.Fatalf("expected decoding to not be done yet")
   160  	}
   161  
   162  	// Retrieves </Struct> end element tag corresponding to <Struct> tag.
   163  	// Since we got the end element that corresponds to the start element being track, we are done decoding.
   164  	token, done, err = nodeDecoder.Token()
   165  	if err != nil {
   166  		t.Fatalf("Expected no error, got %v", err)
   167  
   168  	}
   169  
   170  	if !reflect.DeepEqual(expect, token) {
   171  		t.Fatalf("%v != %v", expect, token)
   172  	}
   173  	if !done {
   174  		t.Fatalf("expected decoding to be done as we fetched the end element </Struct>")
   175  	}
   176  }
   177  
   178  func TestXMLNodeDecoder_Value(t *testing.T) {
   179  	cases := map[string]struct {
   180  		responseBody  io.Reader
   181  		expectedValue []byte
   182  		expectedDone  bool
   183  		expectedError string
   184  	}{
   185  		"simple success case": {
   186  			responseBody:  bytes.NewReader([]byte(`<Response>abc</Response>`)),
   187  			expectedValue: []byte(`abc`),
   188  		},
   189  		"no value": {
   190  			responseBody:  bytes.NewReader([]byte(`<Response></Response>`)),
   191  			expectedValue: []byte{},
   192  		},
   193  		"self-closing": {
   194  			responseBody:  bytes.NewReader([]byte(`<Response />`)),
   195  			expectedValue: []byte{},
   196  		},
   197  		"empty body": {
   198  			responseBody:  bytes.NewReader([]byte(``)),
   199  			expectedError: "EOF",
   200  		},
   201  		"start element retrieved": {
   202  			responseBody:  bytes.NewReader([]byte(`<Response><Struct>abc</Struct></Response>`)),
   203  			expectedError: "expected value for Response element, got xml.StartElement type",
   204  		},
   205  	}
   206  
   207  	for name, c := range cases {
   208  		t.Run(name, func(t *testing.T) {
   209  			xmlDecoder := xml.NewDecoder(c.responseBody)
   210  			st, err := FetchRootElement(xmlDecoder)
   211  			if err != nil {
   212  				if len(c.expectedError) == 0 {
   213  					t.Fatalf("Expected no error, got %v", err)
   214  				}
   215  
   216  				if e, a := c.expectedError, err; !strings.Contains(err.Error(), c.expectedError) {
   217  					t.Fatalf("expected error to contain %v, found %v", e, a.Error())
   218  				}
   219  			}
   220  			nodeDecoder := WrapNodeDecoder(xmlDecoder, st)
   221  			token, err := nodeDecoder.Value()
   222  			if err != nil {
   223  				if len(c.expectedError) == 0 {
   224  					t.Fatalf("Expected no error, got %v", err)
   225  				}
   226  
   227  				if e, a := c.expectedError, err; !strings.Contains(err.Error(), c.expectedError) {
   228  					t.Fatalf("expected error to contain %v, found %v", e, a.Error())
   229  				}
   230  			}
   231  
   232  			if !reflect.DeepEqual(c.expectedValue, token) {
   233  				t.Fatalf("%v != %v", c.expectedValue, token)
   234  			}
   235  		})
   236  	}
   237  }
   238  
   239  func Test_FetchXMLRootElement(t *testing.T) {
   240  	cases := map[string]struct {
   241  		responseBody         io.Reader
   242  		expectedStartElement xml.StartElement
   243  		expectedError        string
   244  	}{
   245  		"simple success case": {
   246  			responseBody: bytes.NewReader([]byte(`<Response><Struct>abc</Struct></Response>`)),
   247  			expectedStartElement: xml.StartElement{
   248  				Name: xml.Name{
   249  					Local: "Response",
   250  				},
   251  				Attr: []xml.Attr{},
   252  			},
   253  		},
   254  		"empty body": {
   255  			responseBody:  bytes.NewReader([]byte(``)),
   256  			expectedError: "EOF",
   257  		},
   258  		"with indentation": {
   259  			responseBody: bytes.NewReader([]byte(`	<ErrorResponse>
   260      <Error>
   261          <Type>Sender</Type>
   262          <Code>InvalidGreeting</Code>
   263          <Message>Hi</Message>
   264          <AnotherSetting>setting</AnotherSetting>
   265      </Error>
   266      <RequestId>foo-id</RequestId>
   267  </ErrorResponse>`)),
   268  			expectedStartElement: xml.StartElement{
   269  				Name: xml.Name{
   270  					Local: "ErrorResponse",
   271  				},
   272  				Attr: []xml.Attr{},
   273  			},
   274  		},
   275  		"with preamble": {
   276  			responseBody: bytes.NewReader([]byte(`<?xml version = "1.0" encoding = "UTF-8" standalone = "no" ?>
   277  <ErrorResponse>
   278      <Error>
   279          <Type>Sender</Type>
   280          <Code>InvalidGreeting</Code>
   281          <Message>Hi</Message>
   282          <AnotherSetting>setting</AnotherSetting>
   283      </Error>
   284      <RequestId>foo-id</RequestId>
   285  </ErrorResponse>`)),
   286  			expectedStartElement: xml.StartElement{
   287  				Name: xml.Name{
   288  					Local: "ErrorResponse",
   289  				},
   290  				Attr: []xml.Attr{},
   291  			},
   292  		},
   293  		"with comments": {
   294  			responseBody: bytes.NewReader([]byte(`<!--Sample comment for testing-->
   295  <?xml version = "1.0" encoding = "UTF-8" standalone = "no" ?>
   296  <ErrorResponse>
   297      <Error>
   298          <Type>Sender</Type>
   299          <Code>InvalidGreeting</Code>
   300          <Message>Hi</Message>
   301          <AnotherSetting>setting</AnotherSetting>
   302      </Error>
   303      <RequestId>foo-id</RequestId>
   304  </ErrorResponse>`)),
   305  			expectedStartElement: xml.StartElement{
   306  				Name: xml.Name{
   307  					Local: "ErrorResponse",
   308  				},
   309  				Attr: []xml.Attr{},
   310  			},
   311  		},
   312  	}
   313  
   314  	for name, c := range cases {
   315  		t.Run(name, func(t *testing.T) {
   316  			decoder := xml.NewDecoder(c.responseBody)
   317  			st, err := FetchRootElement(decoder)
   318  			if err != nil {
   319  				if len(c.expectedError) == 0 {
   320  					t.Fatalf("Expected no error, got %v", err)
   321  				}
   322  
   323  				if e, a := c.expectedError, err; !strings.Contains(err.Error(), c.expectedError) {
   324  					t.Fatalf("expected error to contain %v, found %v", e, a.Error())
   325  				}
   326  			}
   327  
   328  			if !reflect.DeepEqual(c.expectedStartElement, st) {
   329  				t.Fatalf("Found diff : %v != %v", c.expectedStartElement, st)
   330  			}
   331  		})
   332  	}
   333  }
   334  

View as plain text