...

Source file src/github.com/launchdarkly/go-jsonstream/v3/internal/commontest/test_values.go

Documentation: github.com/launchdarkly/go-jsonstream/v3/internal/commontest

     1  package commontest
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  )
     7  
     8  // This file is used by test_factory.go to define a standard set of JSON scalar test values.
     9  
    10  type encodingBehavior struct {
    11  	encodeAsHex func(rune) bool
    12  	forParsing  bool
    13  }
    14  
    15  type testValue struct {
    16  	name     string
    17  	encoding string
    18  	value    AnyValue
    19  }
    20  
    21  type numberTestValueBase struct {
    22  	name             string
    23  	val              float64
    24  	encoding         string
    25  	simplestEncoding string
    26  }
    27  
    28  type stringTestValueBase struct {
    29  	name     string
    30  	val      string
    31  	encoding string
    32  }
    33  
    34  func makeBoolTestValues() []testValue {
    35  	return []testValue{
    36  		{"bool true", "true", AnyValue{Kind: BoolValue, Bool: true}},
    37  		{"bool false", "false", AnyValue{Kind: BoolValue, Bool: false}},
    38  	}
    39  }
    40  
    41  func makeNumberTestValues(encodingBehavior encodingBehavior) []testValue {
    42  	var ret []testValue
    43  	for _, v := range []numberTestValueBase{
    44  		{"zero", 0, "0", ""},
    45  		{"int", 3, "3", ""},
    46  		{"int negative", -3, "-3", ""},
    47  		{"int large", 1603312301195, "1603312301195", ""}, // enough magnitude for a millisecond timestamp
    48  		{"float", 3.5, "3.5", ""},
    49  		{"float negative", -3.5, "-3.5", ""},
    50  		{"float with exp and decimal", 3500, "3.5e3", "3500"},
    51  		{"float with Exp and decimal", 3500, "3.5E3", "3500"},
    52  		{"float with exp+ and decimal", 3500, "3.5e+3", "3500"},
    53  		{"float with exp- and decimal", 0.0035, "3.5e-3", "0.0035"},
    54  		{"float with exp but no decimal", 5000, "5e3", "5000"},
    55  		{"float with Exp but no decimal", 5000, "5E3", "5000"},
    56  		{"float with exp+ but no decimal", 5000, "5e+3", "5000"},
    57  		{"float with exp- but no decimal", 0.005, "5e-3", "0.005"},
    58  	} {
    59  		enc := v.encoding
    60  		if !encodingBehavior.forParsing && v.simplestEncoding != "" {
    61  			enc = v.simplestEncoding
    62  		}
    63  		ret = append(ret, testValue{"number " + v.name, enc, AnyValue{Kind: NumberValue, Number: v.val}})
    64  	}
    65  	return ret
    66  }
    67  
    68  func makeStringTestValues(encodingBehavior encodingBehavior, allPermutations bool) []testValue {
    69  	base := []stringTestValueBase{
    70  		{name: "empty", val: "", encoding: `""`},
    71  		{name: "simple", val: "abc", encoding: `"abc"`},
    72  	}
    73  	allEscapeTests := []stringTestValueBase{}
    74  	if allPermutations {
    75  		baseEscapeTests := []stringTestValueBase{
    76  			{val: `"`, encoding: `\"`},
    77  			{val: `\`, encoding: `\\`},
    78  			{val: "\x05", encoding: `\u0005`},
    79  			{val: "\x1c", encoding: `\u001c`},
    80  			{val: "πŸ¦œπŸ¦„πŸ˜‚πŸ§ΆπŸ˜» yes", encoding: "πŸ¦œπŸ¦„πŸ˜‚πŸ§ΆπŸ˜» yes"}, // unescaped multi-byte characters are allowed
    81  		}
    82  		addControlChar := func(str, shortEncoding string) {
    83  			hex := strconv.FormatInt(int64(str[0]), 16)
    84  			if len(hex) == 1 {
    85  				hex = "0" + hex
    86  			}
    87  			encodeAsHex := false
    88  			if encodingBehavior.encodeAsHex != nil {
    89  				encodeAsHex = encodingBehavior.encodeAsHex(rune(str[0]))
    90  			}
    91  			if !encodingBehavior.forParsing && !encodeAsHex {
    92  				baseEscapeTests = append(baseEscapeTests, stringTestValueBase{val: str, encoding: shortEncoding})
    93  			}
    94  			if encodingBehavior.forParsing || encodeAsHex {
    95  				baseEscapeTests = append(baseEscapeTests, stringTestValueBase{val: str, encoding: `\u00` + hex})
    96  			}
    97  		}
    98  		addControlChar("\b", `\b`)
    99  		addControlChar("\t", `\t`)
   100  		addControlChar("\n", `\n`)
   101  		addControlChar("\f", `\f`)
   102  		addControlChar("\r", `\r`)
   103  		if encodingBehavior.forParsing {
   104  			// These escapes are not used when writing, but may be encountered when parsing
   105  			baseEscapeTests = append(baseEscapeTests, stringTestValueBase{val: "/", encoding: `\/`})
   106  			baseEscapeTests = append(baseEscapeTests, stringTestValueBase{val: "γ‚‚", encoding: `\u3082`})
   107  		}
   108  		for _, et := range baseEscapeTests {
   109  			allEscapeTests = append(allEscapeTests, et)
   110  			addTransformed := func(valFn func(string) string, encFn func(string) string) {
   111  				tt := stringTestValueBase{
   112  					val:      valFn(et.val),
   113  					encoding: encFn(et.encoding),
   114  				}
   115  				allEscapeTests = append(allEscapeTests, tt)
   116  			}
   117  			for _, f := range []string{"%sabcd", "abcd%s", "ab%scd"} {
   118  				addTransformed(func(s string) string { return fmt.Sprintf(f, s) },
   119  					func(s string) string { return fmt.Sprintf(f, s) })
   120  			}
   121  			for _, et2 := range baseEscapeTests {
   122  				for _, f := range []string{"%s%sabcd", "ab%s%scd", "a%sbc%sd", "abcd%s%s"} {
   123  					addTransformed(func(s string) string { return fmt.Sprintf(f, s, et2.val) },
   124  						func(s string) string { return fmt.Sprintf(f, s, et2.encoding) })
   125  				}
   126  			}
   127  		}
   128  	} else {
   129  		// When we're testing nested data structures, we don't need to cover all those permutations of
   130  		// escape sequences-- we can assume that the same string encoding logic applies as it would for
   131  		// a single value.
   132  		allEscapeTests = []stringTestValueBase{{val: "simple\tescape", encoding: `simple\tescape`}}
   133  	}
   134  	for i, et := range allEscapeTests {
   135  		st := stringTestValueBase{
   136  			name:     fmt.Sprintf("with escapes %d", i+1),
   137  			val:      et.val,
   138  			encoding: `"` + et.encoding + `"`,
   139  		}
   140  		base = append(base, st)
   141  	}
   142  	ret := make([]testValue, 0, len(base))
   143  	for _, b := range base {
   144  		ret = append(ret, testValue{name: "string " + b.name, encoding: b.encoding,
   145  			value: AnyValue{Kind: StringValue, String: b.val}})
   146  	}
   147  	return ret
   148  }
   149  
   150  func MakeWhitespaceOptions() map[string]string {
   151  	return map[string]string{"spaces": "  ", "tab": "\t", "newline": "\n"}
   152  }
   153  

View as plain text