~ubuntu-branches/ubuntu/saucy/juju-core/saucy-proposed

« back to all changes in this revision

Viewing changes to src/launchpad.net/juju-core/charm/config_test.go

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-07-11 17:18:27 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20130711171827-vjqkg40r0dlf7ys2
Tags: 1.11.2-0ubuntu1
* New upstream release.
* Make juju-core the default juju (LP: #1190634):
  - d/control: Add virtual package juju -> juju-core.
  - d/juju-core.postinst.in: Bump priority of alternatives over that of
    python juju packages.
* Enable for all architectures (LP: #1172505):
  - d/control: Version BD on golang-go to >= 2:1.1.1 to ensure CGO
    support for non-x86 archs, make juju-core Arch: any.
  - d/README.source: Dropped - no longer required.
* d/watch: Updated for new upstream tarball naming.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2011, 2012, 2013 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
1
4
package charm_test
2
5
 
3
6
import (
4
7
        "bytes"
5
8
        "fmt"
6
 
        "io"
7
 
        "io/ioutil"
8
9
        . "launchpad.net/gocheck"
9
10
        "launchpad.net/juju-core/charm"
10
 
        "launchpad.net/juju-core/testing"
11
 
        "os"
12
 
        "path/filepath"
13
11
)
14
12
 
15
 
var sampleConfig = `
 
13
type ConfigSuite struct {
 
14
        config *charm.Config
 
15
}
 
16
 
 
17
var _ = Suite(&ConfigSuite{})
 
18
 
 
19
func (s *ConfigSuite) SetUpSuite(c *C) {
 
20
        // Just use a single shared config for the whole suite. There's no use case
 
21
        // for mutating a config, we we assume that nobody will do so here.
 
22
        var err error
 
23
        s.config, err = charm.ReadConfig(bytes.NewBuffer([]byte(`
16
24
options:
17
25
  title:
18
26
    default: My Title
19
27
    description: A descriptive title used for the service.
20
28
    type: string
 
29
  subtitle:
 
30
    default: ""
 
31
    description: An optional subtitle used for the service.
21
32
  outlook:
22
33
    description: No default outlook.
23
 
    type: string
 
34
    # type defaults to string in python
24
35
  username:
25
36
    default: admin001
26
37
    description: The name of the initial account (given admin permissions).
34
45
  reticulate-splines:
35
46
    description: Whether to reticulate splines on launch, or not.
36
47
    type: boolean
37
 
`
38
 
 
39
 
func repoConfig(name string) io.Reader {
40
 
        charmDir := testing.Charms.DirPath(name)
41
 
        file, err := os.Open(filepath.Join(charmDir, "config.yaml"))
42
 
        if err != nil {
43
 
                panic(err)
44
 
        }
45
 
        defer file.Close()
46
 
        data, err := ioutil.ReadAll(file)
47
 
        if err != nil {
48
 
                panic(err)
49
 
        }
50
 
        return bytes.NewBuffer(data)
51
 
}
52
 
 
53
 
type ConfigSuite struct{}
54
 
 
55
 
var _ = Suite(&ConfigSuite{})
56
 
 
57
 
func (s *ConfigSuite) TestReadConfig(c *C) {
58
 
        config, err := charm.ReadConfig(repoConfig("dummy"))
 
48
`)))
59
49
        c.Assert(err, IsNil)
60
 
        c.Assert(config.Options["title"], DeepEquals,
61
 
                charm.Option{
 
50
}
 
51
 
 
52
func (s *ConfigSuite) TestReadSample(c *C) {
 
53
        c.Assert(s.config.Options, DeepEquals, map[string]charm.Option{
 
54
                "title": {
62
55
                        Default:     "My Title",
63
56
                        Description: "A descriptive title used for the service.",
64
57
                        Type:        "string",
65
58
                },
66
 
        )
 
59
                "subtitle": {
 
60
                        Default:     "",
 
61
                        Description: "An optional subtitle used for the service.",
 
62
                        Type:        "string",
 
63
                },
 
64
                "username": {
 
65
                        Default:     "admin001",
 
66
                        Description: "The name of the initial account (given admin permissions).",
 
67
                        Type:        "string",
 
68
                },
 
69
                "outlook": {
 
70
                        Description: "No default outlook.",
 
71
                        Type:        "string",
 
72
                },
 
73
                "skill-level": {
 
74
                        Description: "A number indicating skill.",
 
75
                        Type:        "int",
 
76
                },
 
77
                "agility-ratio": {
 
78
                        Description: "A number from 0 to 1 indicating agility.",
 
79
                        Type:        "float",
 
80
                },
 
81
                "reticulate-splines": {
 
82
                        Description: "Whether to reticulate splines on launch, or not.",
 
83
                        Type:        "boolean",
 
84
                },
 
85
        })
 
86
}
 
87
 
 
88
func (s *ConfigSuite) TestDefaultSettings(c *C) {
 
89
        c.Assert(s.config.DefaultSettings(), DeepEquals, charm.Settings{
 
90
                "title":              "My Title",
 
91
                "subtitle":           "",
 
92
                "username":           "admin001",
 
93
                "outlook":            nil,
 
94
                "skill-level":        nil,
 
95
                "agility-ratio":      nil,
 
96
                "reticulate-splines": nil,
 
97
        })
 
98
}
 
99
 
 
100
func (s *ConfigSuite) TestFilterSettings(c *C) {
 
101
        settings := s.config.FilterSettings(charm.Settings{
 
102
                "title":              "something valid",
 
103
                "username":           nil,
 
104
                "unknown":            "whatever",
 
105
                "outlook":            "",
 
106
                "skill-level":        5.5,
 
107
                "agility-ratio":      true,
 
108
                "reticulate-splines": "hullo",
 
109
        })
 
110
        c.Assert(settings, DeepEquals, charm.Settings{
 
111
                "title":    "something valid",
 
112
                "username": nil,
 
113
                "outlook":  nil,
 
114
        })
 
115
}
 
116
 
 
117
func (s *ConfigSuite) TestValidateSettings(c *C) {
 
118
        for i, test := range []struct {
 
119
                info   string
 
120
                input  charm.Settings
 
121
                expect charm.Settings
 
122
                err    string
 
123
        }{{
 
124
                info:   "nil settings are valid",
 
125
                expect: charm.Settings{},
 
126
        }, {
 
127
                info:  "empty settings are valid",
 
128
                input: charm.Settings{},
 
129
        }, {
 
130
                info:  "unknown keys are not valid",
 
131
                input: charm.Settings{"foo": nil},
 
132
                err:   `unknown option "foo"`,
 
133
        }, {
 
134
                info: "nil is valid for every value type",
 
135
                input: charm.Settings{
 
136
                        "outlook":            nil,
 
137
                        "skill-level":        nil,
 
138
                        "agility-ratio":      nil,
 
139
                        "reticulate-splines": nil,
 
140
                },
 
141
        }, {
 
142
                info: "correctly-typed values are valid",
 
143
                input: charm.Settings{
 
144
                        "outlook":            "stormy",
 
145
                        "skill-level":        int64(123),
 
146
                        "agility-ratio":      0.5,
 
147
                        "reticulate-splines": true,
 
148
                },
 
149
        }, {
 
150
                info:   "empty string-typed values become nil",
 
151
                input:  charm.Settings{"outlook": ""},
 
152
                expect: charm.Settings{"outlook": nil},
 
153
        }, {
 
154
                info: "almost-correctly-typed values are valid",
 
155
                input: charm.Settings{
 
156
                        "skill-level":   123,
 
157
                        "agility-ratio": float32(0.5),
 
158
                },
 
159
                expect: charm.Settings{
 
160
                        "skill-level":   int64(123),
 
161
                        "agility-ratio": 0.5,
 
162
                },
 
163
        }, {
 
164
                info:  "bad string",
 
165
                input: charm.Settings{"outlook": false},
 
166
                err:   `option "outlook" expected string, got false`,
 
167
        }, {
 
168
                info:  "bad int",
 
169
                input: charm.Settings{"skill-level": 123.4},
 
170
                err:   `option "skill-level" expected int, got 123.4`,
 
171
        }, {
 
172
                info:  "bad float",
 
173
                input: charm.Settings{"agility-ratio": "cheese"},
 
174
                err:   `option "agility-ratio" expected float, got "cheese"`,
 
175
        }, {
 
176
                info:  "bad boolean",
 
177
                input: charm.Settings{"reticulate-splines": 101},
 
178
                err:   `option "reticulate-splines" expected boolean, got 101`,
 
179
        }} {
 
180
                c.Logf("test %d: %s", i, test.info)
 
181
                result, err := s.config.ValidateSettings(test.input)
 
182
                if test.err != "" {
 
183
                        c.Check(err, ErrorMatches, test.err)
 
184
                } else {
 
185
                        c.Check(err, IsNil)
 
186
                        if test.expect == nil {
 
187
                                c.Check(result, DeepEquals, test.input)
 
188
                        } else {
 
189
                                c.Check(result, DeepEquals, test.expect)
 
190
                        }
 
191
                }
 
192
        }
 
193
}
 
194
 
 
195
var settingsWithNils = charm.Settings{
 
196
        "outlook":            nil,
 
197
        "skill-level":        nil,
 
198
        "agility-ratio":      nil,
 
199
        "reticulate-splines": nil,
 
200
}
 
201
 
 
202
var settingsWithValues = charm.Settings{
 
203
        "outlook":            "whatever",
 
204
        "skill-level":        int64(123),
 
205
        "agility-ratio":      2.22,
 
206
        "reticulate-splines": true,
 
207
}
 
208
 
 
209
func (s *ConfigSuite) TestParseSettingsYAML(c *C) {
 
210
        for i, test := range []struct {
 
211
                info   string
 
212
                yaml   string
 
213
                key    string
 
214
                expect charm.Settings
 
215
                err    string
 
216
        }{{
 
217
                info: "bad structure",
 
218
                yaml: "`",
 
219
                err:  `cannot parse settings data: .*`,
 
220
        }, {
 
221
                info: "bad key",
 
222
                yaml: "{}",
 
223
                key:  "blah",
 
224
                err:  `no settings found for "blah"`,
 
225
        }, {
 
226
                info: "bad settings key",
 
227
                yaml: "blah:\n  ping: pong",
 
228
                key:  "blah",
 
229
                err:  `unknown option "ping"`,
 
230
        }, {
 
231
                info: "bad type for string",
 
232
                yaml: "blah:\n  outlook: 123",
 
233
                key:  "blah",
 
234
                err:  `option "outlook" expected string, got 123`,
 
235
        }, {
 
236
                info: "bad type for int",
 
237
                yaml: "blah:\n  skill-level: 12.345",
 
238
                key:  "blah",
 
239
                err:  `option "skill-level" expected int, got 12.345`,
 
240
        }, {
 
241
                info: "bad type for float",
 
242
                yaml: "blah:\n  agility-ratio: blob",
 
243
                key:  "blah",
 
244
                err:  `option "agility-ratio" expected float, got "blob"`,
 
245
        }, {
 
246
                info: "bad type for boolean",
 
247
                yaml: "blah:\n  reticulate-splines: 123",
 
248
                key:  "blah",
 
249
                err:  `option "reticulate-splines" expected boolean, got 123`,
 
250
        }, {
 
251
                info: "bad string for int",
 
252
                yaml: "blah:\n  skill-level: cheese",
 
253
                key:  "blah",
 
254
                err:  `option "skill-level" expected int, got "cheese"`,
 
255
        }, {
 
256
                info: "bad string for float",
 
257
                yaml: "blah:\n  agility-ratio: blob",
 
258
                key:  "blah",
 
259
                err:  `option "agility-ratio" expected float, got "blob"`,
 
260
        }, {
 
261
                info: "bad string for boolean",
 
262
                yaml: "blah:\n  reticulate-splines: cannonball",
 
263
                key:  "blah",
 
264
                err:  `option "reticulate-splines" expected boolean, got "cannonball"`,
 
265
        }, {
 
266
                info:   "empty dict is valid",
 
267
                yaml:   "blah: {}",
 
268
                key:    "blah",
 
269
                expect: charm.Settings{},
 
270
        }, {
 
271
                info: "nil values are valid",
 
272
                yaml: `blah:
 
273
            outlook: null
 
274
            skill-level: null
 
275
            agility-ratio: null
 
276
            reticulate-splines: null`,
 
277
                key:    "blah",
 
278
                expect: settingsWithNils,
 
279
        }, {
 
280
                info: "empty strings are considered nil",
 
281
                yaml: `blah:
 
282
            outlook: ""
 
283
            skill-level: ""
 
284
            agility-ratio: ""
 
285
            reticulate-splines: ""`,
 
286
                key:    "blah",
 
287
                expect: settingsWithNils,
 
288
        }, {
 
289
                info: "appropriate strings are valid",
 
290
                yaml: `blah:
 
291
            outlook: whatever
 
292
            skill-level: "123"
 
293
            agility-ratio: "2.22"
 
294
            reticulate-splines: "true"`,
 
295
                key:    "blah",
 
296
                expect: settingsWithValues,
 
297
        }, {
 
298
                info: "appropriate types are valid",
 
299
                yaml: `blah:
 
300
            outlook: whatever
 
301
            skill-level: 123
 
302
            agility-ratio: 2.22
 
303
            reticulate-splines: y`,
 
304
                key:    "blah",
 
305
                expect: settingsWithValues,
 
306
        }} {
 
307
                c.Logf("test %d: %s", i, test.info)
 
308
                result, err := s.config.ParseSettingsYAML([]byte(test.yaml), test.key)
 
309
                if test.err != "" {
 
310
                        c.Check(err, ErrorMatches, test.err)
 
311
                } else {
 
312
                        c.Check(err, IsNil)
 
313
                        c.Check(result, DeepEquals, test.expect)
 
314
                }
 
315
        }
 
316
}
 
317
 
 
318
func (s *ConfigSuite) TestParseSettingsStrings(c *C) {
 
319
        for i, test := range []struct {
 
320
                info   string
 
321
                input  map[string]string
 
322
                expect charm.Settings
 
323
                err    string
 
324
        }{{
 
325
                info:   "nil map is valid",
 
326
                expect: charm.Settings{},
 
327
        }, {
 
328
                info:   "empty map is valid",
 
329
                input:  map[string]string{},
 
330
                expect: charm.Settings{},
 
331
        }, {
 
332
                info: "empty strings are nil values",
 
333
                input: map[string]string{
 
334
                        "outlook":            "",
 
335
                        "skill-level":        "",
 
336
                        "agility-ratio":      "",
 
337
                        "reticulate-splines": "",
 
338
                },
 
339
                expect: settingsWithNils,
 
340
        }, {
 
341
                info: "strings are converted",
 
342
                input: map[string]string{
 
343
                        "outlook":            "whatever",
 
344
                        "skill-level":        "123",
 
345
                        "agility-ratio":      "2.22",
 
346
                        "reticulate-splines": "true",
 
347
                },
 
348
                expect: settingsWithValues,
 
349
        }, {
 
350
                info:  "bad string for int",
 
351
                input: map[string]string{"skill-level": "cheese"},
 
352
                err:   `option "skill-level" expected int, got "cheese"`,
 
353
        }, {
 
354
                info:  "bad string for float",
 
355
                input: map[string]string{"agility-ratio": "blob"},
 
356
                err:   `option "agility-ratio" expected float, got "blob"`,
 
357
        }, {
 
358
                info:  "bad string for boolean",
 
359
                input: map[string]string{"reticulate-splines": "cannonball"},
 
360
                err:   `option "reticulate-splines" expected boolean, got "cannonball"`,
 
361
        }} {
 
362
                c.Logf("test %d: %s", i, test.info)
 
363
                result, err := s.config.ParseSettingsStrings(test.input)
 
364
                if test.err != "" {
 
365
                        c.Check(err, ErrorMatches, test.err)
 
366
                } else {
 
367
                        c.Check(err, IsNil)
 
368
                        c.Check(result, DeepEquals, test.expect)
 
369
                }
 
370
        }
67
371
}
68
372
 
69
373
func (s *ConfigSuite) TestConfigError(c *C) {
70
374
        _, err := charm.ReadConfig(bytes.NewBuffer([]byte(`options: {t: {type: foo}}`)))
71
 
        c.Assert(err, ErrorMatches, `config: options.t.type: unexpected value.*`)
 
375
        c.Assert(err, ErrorMatches, `invalid config: option "t" has unknown type "foo"`)
72
376
}
73
377
 
74
378
func (s *ConfigSuite) TestDefaultType(c *C) {
81
385
 
82
386
        assertDefault("boolean", "true", true)
83
387
        assertDefault("string", "golden grahams", "golden grahams")
 
388
        assertDefault("string", `""`, "")
84
389
        assertDefault("float", "2.2e11", 2.2e11)
85
390
        assertDefault("int", "99", int64(99))
86
391
 
87
 
        assertTypeError := func(type_ string, value string) {
88
 
                config := fmt.Sprintf(`options: {t: {type: %s, default: %s}}`, type_, value)
 
392
        assertTypeError := func(type_, str, value string) {
 
393
                config := fmt.Sprintf(`options: {t: {type: %s, default: %s}}`, type_, str)
89
394
                _, err := charm.ReadConfig(bytes.NewBuffer([]byte(config)))
90
 
                expected := fmt.Sprintf(`Bad default for "t": %s is not of type %s`, value, type_)
 
395
                expected := fmt.Sprintf(`invalid config default: option "t" expected %s, got %s`, type_, value)
91
396
                c.Assert(err, ErrorMatches, expected)
92
397
        }
93
398
 
94
 
        assertTypeError("boolean", "henry")
95
 
        assertTypeError("string", "2.5")
96
 
        assertTypeError("float", "blob")
97
 
        assertTypeError("int", "33.2")
98
 
}
99
 
 
100
 
func (s *ConfigSuite) TestParseSample(c *C) {
101
 
        config, err := charm.ReadConfig(bytes.NewBuffer([]byte(sampleConfig)))
102
 
        c.Assert(err, IsNil)
103
 
 
104
 
        opt := config.Options
105
 
        c.Assert(opt["title"], DeepEquals,
106
 
                charm.Option{
107
 
                        Default:     "My Title",
108
 
                        Description: "A descriptive title used for the service.",
109
 
                        Type:        "string",
110
 
                },
111
 
        )
112
 
        c.Assert(opt["outlook"], DeepEquals,
113
 
                charm.Option{
114
 
                        Description: "No default outlook.",
115
 
                        Type:        "string",
116
 
                },
117
 
        )
118
 
        c.Assert(opt["username"], DeepEquals,
119
 
                charm.Option{
120
 
                        Default:     "admin001",
121
 
                        Description: "The name of the initial account (given admin permissions).",
122
 
                        Type:        "string",
123
 
                },
124
 
        )
125
 
        c.Assert(opt["skill-level"], DeepEquals,
126
 
                charm.Option{
127
 
                        Description: "A number indicating skill.",
128
 
                        Type:        "int",
129
 
                },
130
 
        )
131
 
        c.Assert(opt["reticulate-splines"], DeepEquals,
132
 
                charm.Option{
133
 
                        Description: "Whether to reticulate splines on launch, or not.",
134
 
                        Type:        "boolean",
135
 
                },
136
 
        )
137
 
}
138
 
 
139
 
func (s *ConfigSuite) TestValidate(c *C) {
140
 
        config, err := charm.ReadConfig(bytes.NewBuffer([]byte(sampleConfig)))
141
 
        c.Assert(err, IsNil)
142
 
 
143
 
        input := map[string]string{
144
 
                "title":   "Helpful Title",
145
 
                "outlook": "Peachy",
146
 
        }
147
 
 
148
 
        // This should include an overridden value, a default and a new value.
149
 
        expected := map[string]interface{}{
150
 
                "title":    "Helpful Title",
151
 
                "outlook":  "Peachy",
152
 
                "username": "admin001",
153
 
        }
154
 
 
155
 
        output, err := config.Validate(input)
156
 
        c.Assert(err, IsNil)
157
 
        c.Assert(output, DeepEquals, expected)
158
 
 
159
 
        // Check whether float conversion is working.
160
 
        input["agility-ratio"] = "0.5"
161
 
        input["skill-level"] = "7"
162
 
        expected["agility-ratio"] = 0.5
163
 
        expected["skill-level"] = int64(7)
164
 
        output, err = config.Validate(input)
165
 
        c.Assert(err, IsNil)
166
 
        c.Assert(output, DeepEquals, expected)
167
 
 
168
 
        // Check whether float errors are caught.
169
 
        input["agility-ratio"] = "foo"
170
 
        output, err = config.Validate(input)
171
 
        c.Assert(err, ErrorMatches, `Value for "agility-ratio" is not a float: "foo"`)
172
 
        input["agility-ratio"] = "0.5"
173
 
 
174
 
        // Check whether int errors are caught.
175
 
        input["skill-level"] = "foo"
176
 
        output, err = config.Validate(input)
177
 
        c.Assert(err, ErrorMatches, `Value for "skill-level" is not an int: "foo"`)
178
 
        input["skill-level"] = "7"
179
 
 
180
 
        // Check whether boolean errors are caught.
181
 
        input["reticulate-splines"] = "maybe"
182
 
        output, err = config.Validate(input)
183
 
        c.Assert(err, ErrorMatches, `Value for "reticulate-splines" is not a boolean: "maybe"`)
184
 
        input["reticulate-splines"] = "false"
185
 
 
186
 
        // Now try to set a value outside the expected.
187
 
        input["bad"] = "value"
188
 
        output, err = config.Validate(input)
189
 
        c.Assert(output, IsNil)
190
 
        c.Assert(err, ErrorMatches, `Unknown configuration option: "bad"`)
191
 
}
192
 
 
193
 
var convertTests = []struct {
194
 
        summary string
195
 
        input   map[string]interface{}
196
 
        expect  map[string]interface{}
197
 
        err     string
198
 
}{{
199
 
        // Schema defaults are ignored.
200
 
        summary: "valid strings",
201
 
        input: map[string]interface{}{
202
 
                "title":   "Helpful Title",
203
 
                "outlook": "Peachy",
204
 
        },
205
 
        expect: map[string]interface{}{
206
 
                "title":   "Helpful Title",
207
 
                "outlook": "Peachy",
208
 
        },
209
 
}, {
210
 
        // Integers are always int64 in YAML, where the input is usually coming from.
211
 
        summary: "valid integers and floats",
212
 
        input: map[string]interface{}{
213
 
                "agility-ratio": 0.5,
214
 
                "skill-level":   int64(7),
215
 
        },
216
 
        expect: map[string]interface{}{
217
 
                "agility-ratio": 0.5,
218
 
                "skill-level":   int64(7),
219
 
        },
220
 
}, {
221
 
        summary: "valid booleans",
222
 
        input:   map[string]interface{}{"reticulate-splines": true},
223
 
        expect:  map[string]interface{}{"reticulate-splines": true},
224
 
}, {
225
 
        summary: "invalid type error with floats",
226
 
        input:   map[string]interface{}{"agility-ratio": "bar"},
227
 
        err:     `unexpected type in service configuration "agility-ratio"="bar"; expected float`,
228
 
}, {
229
 
        summary: "invalid type error with integers",
230
 
        input:   map[string]interface{}{"skill-level": "foo"},
231
 
        err:     `unexpected type in service configuration "skill-level"="foo"; expected int`,
232
 
}, {
233
 
        summary: "invalid type error with booleans",
234
 
        input:   map[string]interface{}{"reticulate-splines": "maybe"},
235
 
        err:     `unexpected type in service configuration "reticulate-splines"="maybe"; expected boolean`,
236
 
}, {
237
 
        summary: "with value not in the schema (ignored)",
238
 
        input:   map[string]interface{}{"bad": "value"},
239
 
        expect:  map[string]interface{}{},
240
 
}}
241
 
 
242
 
func (s *ConfigSuite) TestConvert(c *C) {
243
 
        config, err := charm.ReadConfig(bytes.NewBuffer([]byte(sampleConfig)))
244
 
        c.Assert(err, IsNil)
245
 
 
246
 
        for i, t := range convertTests {
247
 
                c.Logf("test %d: %s", i, t.summary)
248
 
                output, err := config.Convert(t.input)
249
 
                if t.err != "" {
250
 
                        c.Assert(err, ErrorMatches, t.err)
251
 
                } else {
252
 
                        c.Assert(err, IsNil)
253
 
                        c.Assert(output, DeepEquals, t.expect)
254
 
                }
255
 
        }
 
399
        assertTypeError("boolean", "henry", `"henry"`)
 
400
        assertTypeError("string", "2.5", "2.5")
 
401
        assertTypeError("float", "123", "123")
 
402
        assertTypeError("int", "true", "true")
256
403
}