blob: f3f42a6fcd71aec3e863210b1be3d67a1f292517 [file] [log] [blame]
// Copyright 2017 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
package csource
import (
"fmt"
"reflect"
"testing"
)
//{Threaded:true Collide:true Repeat:true Procs:1 Sandbox:none Fault:false FaultCall:-1 FaultNth:0 EnableTun:true UseTmpDir:true HandleSegv:true WaitRepeat:true Debug:false Repro:false}
func TestParseOptions(t *testing.T) {
for _, opts := range allOptionsSingle() {
data := opts.Serialize()
got, err := DeserializeOptions(data)
if err != nil {
t.Fatalf("failed to deserialize %q: %v", data, err)
}
if !reflect.DeepEqual(got, opts) {
t.Fatalf("opts changed, got:\n%+v\nwant:\n%+v", got, opts)
}
}
}
func TestParseOptionsCanned(t *testing.T) {
// Dashboard stores csource options with syzkaller reproducers,
// so we need to be able to parse old formats.
canned := map[string]Options{
"{Threaded:true Collide:true Repeat:true Procs:1 Sandbox:none Fault:false FaultCall:-1 FaultNth:0 EnableTun:true UseTmpDir:true HandleSegv:true WaitRepeat:true Debug:false Repro:false}": Options{
Threaded: true,
Collide: true,
Repeat: true,
Procs: 1,
Sandbox: "none",
Fault: false,
FaultCall: -1,
FaultNth: 0,
EnableTun: true,
UseTmpDir: true,
HandleSegv: true,
WaitRepeat: true,
Debug: false,
Repro: false,
},
"{Threaded:true Collide:true Repeat:true Procs:1 Sandbox: Fault:false FaultCall:-1 FaultNth:0 EnableTun:true UseTmpDir:true HandleSegv:true WaitRepeat:true Debug:false Repro:false}": Options{
Threaded: true,
Collide: true,
Repeat: true,
Procs: 1,
Sandbox: "",
Fault: false,
FaultCall: -1,
FaultNth: 0,
EnableTun: true,
UseTmpDir: true,
HandleSegv: true,
WaitRepeat: true,
Debug: false,
Repro: false,
},
}
for data, want := range canned {
got, err := DeserializeOptions([]byte(data))
if err != nil {
t.Fatalf("failed to deserialize %q: %v", data, err)
}
if !reflect.DeepEqual(got, want) {
t.Fatalf("deserialize %q\ngot:\n%+v\nwant:\n%+v", data, got, want)
}
}
}
func allOptionsSingle() []Options {
var opts []Options
fields := reflect.TypeOf(Options{}).NumField()
for i := 0; i < fields; i++ {
opts = append(opts, enumerateField(Options{}, i)...)
}
return opts
}
func allOptionsPermutations() []Options {
opts := []Options{Options{}}
fields := reflect.TypeOf(Options{}).NumField()
for i := 0; i < fields; i++ {
var newOpts []Options
for _, opt := range opts {
newOpts = append(newOpts, enumerateField(opt, i)...)
}
opts = newOpts
}
return opts
}
func enumerateField(opt Options, field int) []Options {
var opts []Options
s := reflect.ValueOf(&opt).Elem()
fldName := s.Type().Field(field).Name
fld := s.Field(field)
if fldName == "Sandbox" {
for _, sandbox := range []string{"", "none", "setuid", "namespace"} {
fld.SetString(sandbox)
opts = append(opts, opt)
}
} else if fldName == "Procs" {
for _, procs := range []int64{1, 4} {
fld.SetInt(procs)
opts = append(opts, opt)
}
} else if fldName == "FaultCall" {
opts = append(opts, opt)
} else if fldName == "FaultNth" {
opts = append(opts, opt)
} else if fld.Kind() == reflect.Bool {
for _, v := range []bool{false, true} {
fld.SetBool(v)
opts = append(opts, opt)
}
} else {
panic(fmt.Sprintf("field '%v' is not boolean", fldName))
}
var checked []Options
for _, opt := range opts {
if err := opt.Check(); err == nil {
checked = append(checked, opt)
}
}
return checked
}