...

Source file src/victortoso.com/qapi-go/pkg/qapi/alternates_test.go

Documentation: victortoso.com/qapi-go/pkg/qapi

     1  package qapi
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"reflect"
     7  	"strings"
     8  	"testing"
     9  )
    10  
    11  func TestTypeStrOrNull(t *testing.T) {
    12  	var nilPtr *string
    13  	validString := "QAPI Spec"
    14  	emptyString := ""
    15  
    16  	structToJson := []struct {
    17  		s           StrOrNull
    18  		output      string
    19  		shouldError bool
    20  		errMsg      string
    21  	}{
    22  		// Evaluates to JSON Null
    23  		{s: StrOrNull{}, output: `null`},
    24  		{s: StrOrNull{Value: nilPtr}, output: `null`},
    25  		// Evaluates to a JSON String
    26  		{s: StrOrNull{Value: "QEMU 42"}, output: `"QEMU 42"`},
    27  		{s: StrOrNull{Value: &validString}, output: fmt.Sprintf(`"%s"`, validString)},
    28  		{s: StrOrNull{Value: &emptyString}, output: `""`},
    29  		// Errors
    30  		{s: StrOrNull{Value: 42}, shouldError: true, errMsg: "Type is not supported"},
    31  	}
    32  
    33  	for _, data := range structToJson {
    34  		b, err := json.Marshal(&data.s)
    35  		if err != nil {
    36  			if data.shouldError {
    37  				if !strings.Contains(err.Error(), data.errMsg) {
    38  					t.Fatalf("Error messages do not match:\nGot:%s\nHas:%s\n", err.Error(), data.errMsg)
    39  				}
    40  			} else {
    41  				t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
    42  			}
    43  		} else if strings.Compare(string(b), string(data.output)) != 0 {
    44  			t.Fatalf("Marshal does not match:\nGot:%s\nHas:%s\n", string(b), string(data.output))
    45  		}
    46  	}
    47  
    48  	jsonToStruct := []struct {
    49  		input         string
    50  		expectedType  string
    51  		expectedValue string
    52  		shouldError   bool
    53  		errMsg        string
    54  	}{
    55  		// JSON Null -> nil
    56  		{input: `null`, expectedType: "<nil>"},
    57  		// JSON String -> string
    58  		{input: `""`, expectedType: "string", expectedValue: ""},
    59  		{input: `"Pineapple pizza"`, expectedType: "string", expectedValue: "Pineapple pizza"},
    60  		// Errors
    61  		{input: `42`, shouldError: true, errMsg: "Unsupported type"},
    62  	}
    63  
    64  	for _, data := range jsonToStruct {
    65  		s := StrOrNull{}
    66  		if err := json.Unmarshal([]byte(data.input), &s); err != nil {
    67  			if data.shouldError {
    68  				if !strings.Contains(err.Error(), data.errMsg) {
    69  					t.Fatalf("Error messages do not match:\nGot:%s\nHas:%s\n", err.Error(), data.errMsg)
    70  				}
    71  			} else {
    72  				t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
    73  			}
    74  		} else {
    75  			gotType := fmt.Sprintf("%T", s.Value)
    76  			if strings.Compare(gotType, string(data.expectedType)) != 0 {
    77  				t.Fatalf("Marshal does not match:\nGot:%s\nHas:%s\n", gotType, string(data.expectedType))
    78  			}
    79  			if s.Value != nil && strings.Compare(s.Value.(string), data.expectedValue) != 0 {
    80  				t.Fatalf("Marshal value does not match:\nGot:%s\nHas:%s\n", s.Value.(string), string(data.expectedValue))
    81  			}
    82  		}
    83  	}
    84  }
    85  
    86  func TestTypeBlockdevRef(t *testing.T) {
    87  	var nilPtr *string
    88  	validString := "Some ID"
    89  
    90  	structToJson := []struct {
    91  		s           BlockdevRef
    92  		output      string
    93  		shouldError bool
    94  		errMsg      string
    95  	}{
    96  		// String
    97  		{s: BlockdevRef{Value: `my-existing-block-device-id`}, output: `"my-existing-block-device-id"`},
    98  		{s: BlockdevRef{Value: ""}, output: `""`},
    99  		{s: BlockdevRef{Value: validString}, output: fmt.Sprintf(`"%s"`, validString)},
   100  		// BlockdevOptions
   101  		{s: BlockdevRef{Value: func() BlockdevOptions {
   102  			qcow2 := BlockdevOptionsQcow2{}
   103  			qcow2.File = BlockdevRef{Value: "/some/place/my-image"}
   104  			opt := BlockdevOptions{}
   105  			opt.Driver = BlockdevDriverQcow2
   106  			opt.Value = qcow2
   107  			return opt
   108  		}()}, output: `{"driver":"qcow2","file":"/some/place/my-image"}`},
   109  		// Errors
   110  		{s: BlockdevRef{Value: 42}, shouldError: true, errMsg: "Type is not supported"},
   111  		{s: BlockdevRef{Value: &validString}, shouldError: true, errMsg: "Type is not supported"},
   112  		{s: BlockdevRef{Value: nilPtr}, shouldError: true, errMsg: "Type is not supported"},
   113  	}
   114  
   115  	for _, data := range structToJson {
   116  		b, err := json.Marshal(data.s)
   117  		if err != nil {
   118  			if data.shouldError {
   119  				if !strings.Contains(err.Error(), data.errMsg) {
   120  					t.Fatalf("Error messages do not match:\nGot:%s\nHas:%s\n", err.Error(), data.errMsg)
   121  				}
   122  			} else {
   123  				t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
   124  			}
   125  		} else if strings.Compare(string(b), string(data.output)) != 0 {
   126  			t.Fatalf("Marshal does not match:\nGot:%s\nHas:%s\n", string(b), string(data.output))
   127  		}
   128  
   129  	}
   130  
   131  	jsonToStruct := []struct {
   132  		expected    BlockdevRef
   133  		input       string
   134  		shouldError bool
   135  		errMsg      string
   136  	}{
   137  		// String
   138  		{input: `"my-existing-block-device-id"`, expected: BlockdevRef{Value: `my-existing-block-device-id`}},
   139  		{input: `""`, expected: BlockdevRef{Value: ``}},
   140  		// BlockdevOptions
   141  		{input: `{"driver":"qcow2","file":"/some/place/my-image"}`,
   142  			expected: BlockdevRef{Value: func() BlockdevOptions {
   143  				qcow2 := BlockdevOptionsQcow2{}
   144  				qcow2.File = BlockdevRef{Value: "/some/place/my-image"}
   145  				opt := BlockdevOptions{}
   146  				opt.Driver = BlockdevDriverQcow2
   147  				opt.Value = qcow2
   148  				return opt
   149  			}()}},
   150  		// Errors
   151  		{input: `42`, shouldError: true, errMsg: "Unsupported type"},
   152  	}
   153  
   154  	for _, data := range jsonToStruct {
   155  		k := BlockdevRef{}
   156  		if err := json.Unmarshal([]byte(data.input), &k); err != nil {
   157  			if data.shouldError {
   158  				if !strings.Contains(err.Error(), data.errMsg) {
   159  					t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
   160  				}
   161  			} else {
   162  				t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
   163  			}
   164  		} else if !reflect.DeepEqual(k, data.expected) {
   165  			t.Fatalf("Unexpected error:\n%v\n%v\n", data.expected.Value, k.Value)
   166  		}
   167  	}
   168  }
   169  
   170  func TestTypeBlockdevRefOrNull(t *testing.T) {
   171  	var nilPtr *string
   172  	validString := "Some ID"
   173  
   174  	structToJson := []struct {
   175  		s           BlockdevRefOrNull
   176  		output      string
   177  		shouldError bool
   178  		errMsg      string
   179  	}{
   180  		// Null
   181  		{s: BlockdevRefOrNull{}, output: `null`},
   182  		{s: BlockdevRefOrNull{Value: nilPtr}, output: `null`},
   183  		// String
   184  		{s: BlockdevRefOrNull{Value: `my-existing-block-device-id`}, output: `"my-existing-block-device-id"`},
   185  		{s: BlockdevRefOrNull{Value: ""}, output: `""`},
   186  		{s: BlockdevRefOrNull{Value: validString}, output: fmt.Sprintf(`"%s"`, validString)},
   187  		{s: BlockdevRefOrNull{Value: &validString}, output: fmt.Sprintf(`"%s"`, validString)},
   188  		// BlockdevOptions
   189  		{s: BlockdevRefOrNull{Value: func() BlockdevOptions {
   190  			qcow2 := BlockdevOptionsQcow2{}
   191  			qcow2.File = BlockdevRef{Value: "/some/place/my-image"}
   192  			opt := BlockdevOptions{}
   193  			opt.Driver = BlockdevDriverQcow2
   194  			opt.Value = qcow2
   195  			return opt
   196  		}()}, output: `{"driver":"qcow2","file":"/some/place/my-image"}`},
   197  		// Errors
   198  		{s: BlockdevRefOrNull{Value: 42}, shouldError: true, errMsg: "Type is not supported"},
   199  	}
   200  
   201  	for _, data := range structToJson {
   202  		b, err := json.Marshal(data.s)
   203  		if err != nil {
   204  			if data.shouldError {
   205  				if !strings.Contains(err.Error(), data.errMsg) {
   206  					t.Fatalf("Error messages do not match:\nGot:%s\nHas:%s\n", err.Error(), data.errMsg)
   207  				}
   208  			} else {
   209  				t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
   210  			}
   211  		} else if strings.Compare(string(b), string(data.output)) != 0 {
   212  			t.Fatalf("Marshal does not match:\nGot:%s\nHas:%s\n", string(b), string(data.output))
   213  		}
   214  	}
   215  
   216  	jsonToStruct := []struct {
   217  		expected    BlockdevRefOrNull
   218  		input       string
   219  		shouldError bool
   220  		errMsg      string
   221  	}{
   222  		// Null
   223  		{input: `null`, expected: BlockdevRefOrNull{}},
   224  		// String
   225  		{input: `"my-existing-block-device-id"`, expected: BlockdevRefOrNull{Value: `my-existing-block-device-id`}},
   226  		{input: `""`, expected: BlockdevRefOrNull{Value: ""}},
   227  		// Errors
   228  		{input: `42`, shouldError: true, errMsg: "Unsupported type"},
   229  	}
   230  
   231  	for _, data := range jsonToStruct {
   232  		k := BlockdevRefOrNull{}
   233  		if err := json.Unmarshal([]byte(data.input), &k); err != nil {
   234  			if data.shouldError {
   235  				if !strings.Contains(err.Error(), data.errMsg) {
   236  					t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
   237  				}
   238  			} else {
   239  				t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
   240  			}
   241  		} else if !reflect.DeepEqual(k, data.expected) {
   242  			t.Fatalf("Unexpected error:\n%v\n%v\n", data.expected.Value, k.Value)
   243  		}
   244  	}
   245  }
   246  
   247  func TestTypeQcow2OverlapChecks(t *testing.T) {
   248  	isTrue := true
   249  	cached := Qcow2OverlapCheckModeCached
   250  	modeAll := Qcow2OverlapCheckModeAll
   251  	constant := Qcow2OverlapCheckModeConstant
   252  	none := Qcow2OverlapCheckModeNone
   253  	structToJson := []struct {
   254  		s           Qcow2OverlapChecks
   255  		output      string
   256  		shouldError bool
   257  		errMsg      string
   258  	}{
   259  		// Empty is null, which is removed on omitempty
   260  		{s: Qcow2OverlapChecks{}, output: `null`},
   261  		// Qcow2OverlapCheckFlags
   262  		{s: Qcow2OverlapChecks{Value: Qcow2OverlapCheckFlags{
   263  			Template: &cached,
   264  		}}, output: `{"template":"cached"}`},
   265  		{s: Qcow2OverlapChecks{Value: Qcow2OverlapCheckFlags{
   266  			Template:      &modeAll,
   267  			RefcountTable: &isTrue,
   268  			ActiveL2:      &isTrue,
   269  		}}, output: `{"template":"all","active-l2":true,"refcount-table":true}`},
   270  		// Qcow2OverlapCheckMode
   271  		{s: Qcow2OverlapChecks{Value: &none}, output: `"none"`},
   272  		{s: Qcow2OverlapChecks{Value: &constant}, output: `"constant"`},
   273  		{s: Qcow2OverlapChecks{Value: &cached}, output: `"cached"`},
   274  		{s: Qcow2OverlapChecks{Value: &modeAll}, output: `"all"`},
   275  		// Errors
   276  		{s: Qcow2OverlapChecks{Value: 42}, shouldError: true, errMsg: "Type is not supported"},
   277  		{s: Qcow2OverlapChecks{Value: "forty-two"}, shouldError: true, errMsg: "Type is not supported"},
   278  	}
   279  
   280  	for _, data := range structToJson {
   281  		b, err := json.Marshal(data.s)
   282  		if err != nil {
   283  			if data.shouldError {
   284  				if !strings.Contains(err.Error(), data.errMsg) {
   285  					t.Fatalf("Error messages do not match:\nGot:%s\nHas:%s\n", err.Error(), data.errMsg)
   286  				}
   287  			} else {
   288  				t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
   289  			}
   290  		} else if strings.Compare(string(b), string(data.output)) != 0 {
   291  			t.Fatalf("Marshal does not match:\nGot:%s\nHas:%s\n", string(b), string(data.output))
   292  		}
   293  	}
   294  
   295  	jsonToStruct := []struct {
   296  		expected    Qcow2OverlapChecks
   297  		input       string
   298  		shouldError bool
   299  		errMsg      string
   300  	}{
   301  		// Qcow2OverlapCheckFlags
   302  		{input: `{"template":"cached"}`,
   303  			expected: Qcow2OverlapChecks{Value: Qcow2OverlapCheckFlags{
   304  				Template: &cached,
   305  			}}},
   306  		{input: `{"template":"all","active-l2":true,"refcount-table":true}`,
   307  			expected: Qcow2OverlapChecks{Value: Qcow2OverlapCheckFlags{
   308  				Template:      &modeAll,
   309  				RefcountTable: &isTrue,
   310  				ActiveL2:      &isTrue,
   311  			}}},
   312  		// Qcow2OverlapCheckMode
   313  		{input: `"none"`, expected: Qcow2OverlapChecks{Value: Qcow2OverlapCheckModeNone}},
   314  		{input: `"constant"`, expected: Qcow2OverlapChecks{Value: Qcow2OverlapCheckModeConstant}},
   315  		{input: `"cached"`, expected: Qcow2OverlapChecks{Value: Qcow2OverlapCheckModeCached}},
   316  		{input: `"all"`, expected: Qcow2OverlapChecks{Value: Qcow2OverlapCheckModeAll}},
   317  		// Errors
   318  		{input: `42`, shouldError: true, errMsg: "Unsupported type"},
   319  	}
   320  
   321  	for _, data := range jsonToStruct {
   322  		k := Qcow2OverlapChecks{}
   323  		if err := json.Unmarshal([]byte(data.input), &k); err != nil {
   324  			if data.shouldError {
   325  				if !strings.Contains(err.Error(), data.errMsg) {
   326  					t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
   327  				}
   328  			} else {
   329  				t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
   330  			}
   331  		} else if !reflect.DeepEqual(k, data.expected) {
   332  			t.Fatalf("Unexpected error:\n%v\n%v\n", data.expected.Value, k.Value)
   333  		}
   334  	}
   335  }
   336  
   337  func TestTypeBlockDirtyBitmapMergeSource(t *testing.T) {
   338  	structToJson := []struct {
   339  		s           BlockDirtyBitmapMergeSource
   340  		output      string
   341  		shouldError bool
   342  		errMsg      string
   343  	}{
   344  		// Empty is null, which is removed on omitempty
   345  		{s: BlockDirtyBitmapMergeSource{}, output: `null`},
   346  		// String
   347  		{s: BlockDirtyBitmapMergeSource{Value: "local-bitmap-name-id"}, output: `"local-bitmap-name-id"`},
   348  		// BlockDirtyBitmap
   349  		{s: BlockDirtyBitmapMergeSource{Value: BlockDirtyBitmap{
   350  			Node: "that-node-or-device-id",
   351  			Name: "name-or-dirty-bitmap",
   352  		}}, output: `{"node":"that-node-or-device-id","name":"name-or-dirty-bitmap"}`},
   353  		// Errors
   354  		{s: BlockDirtyBitmapMergeSource{Value: 42}, shouldError: true, errMsg: "Type is not supported"},
   355  	}
   356  
   357  	for _, data := range structToJson {
   358  		b, err := json.Marshal(data.s)
   359  		if err != nil {
   360  			if data.shouldError {
   361  				if !strings.Contains(err.Error(), data.errMsg) {
   362  					t.Fatalf("Error messages do not match:\nGot:%s\nHas:%s\n", err.Error(), data.errMsg)
   363  				}
   364  			} else {
   365  				t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
   366  			}
   367  		} else if strings.Compare(string(b), string(data.output)) != 0 {
   368  			t.Fatalf("Marshal does not match:\nGot:%s\nHas:%s\n", string(b), string(data.output))
   369  		}
   370  	}
   371  
   372  	jsonToStruct := []struct {
   373  		expected    BlockDirtyBitmapMergeSource
   374  		input       string
   375  		shouldError bool
   376  		errMsg      string
   377  	}{
   378  		{input: `"local-bitmap-name-id"`, expected: BlockDirtyBitmapMergeSource{Value: "local-bitmap-name-id"}},
   379  		// BlockDirtyBitmap
   380  		{input: `{"node":"that-node-or-device-id","name":"name-or-dirty-bitmap"}`,
   381  			expected: BlockDirtyBitmapMergeSource{Value: BlockDirtyBitmap{
   382  				Node: "that-node-or-device-id",
   383  				Name: "name-or-dirty-bitmap",
   384  			}}},
   385  		// Errors
   386  		{input: `42`, shouldError: true, errMsg: "Unsupported type"},
   387  	}
   388  
   389  	for _, data := range jsonToStruct {
   390  		k := BlockDirtyBitmapMergeSource{}
   391  		if err := json.Unmarshal([]byte(data.input), &k); err != nil {
   392  			if data.shouldError {
   393  				if !strings.Contains(err.Error(), data.errMsg) {
   394  					t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
   395  				}
   396  			} else {
   397  				t.Fatalf("Unexpected error: %T -> %s\n", data, err.Error())
   398  			}
   399  		} else if !reflect.DeepEqual(k, data.expected) {
   400  			t.Fatalf("Unexpected error:\n%v\n%v\n", data.expected.Value, k.Value)
   401  		}
   402  	}
   403  }
   404  

View as plain text