package models import ( "reflect" "testing" ) // TestPermissionSetRoundTrip: what Value writes, Scan and ParsePermissionSet // read back unchanged; Text is the same text for a plain string column. func TestPermissionSetRoundTrip(t *testing.T) { for _, tc := range []struct { name string set PermissionSet text string // "" stands for NULL back PermissionSet }{ {"allow and deny", PermissionSet{"blog.post": 1, "blog.edit": -1}, `{"blog.edit":-1,"blog.post":1}`, PermissionSet{"blog.post": 1, "blog.edit": -1}}, {"a zero is not stored", PermissionSet{"blog.post": 1, "blog.zero": 0}, `{"blog.post":1}`, PermissionSet{"blog.post": 1}}, {"a wildcard code", PermissionSet{"blog.*": 1}, `{"blog.*":1}`, PermissionSet{"blog.*": 1}}, {"an empty set", PermissionSet{}, "", PermissionSet{}}, {"a nil set", nil, "", PermissionSet{}}, {"only zeros", PermissionSet{"blog.zero": 0}, "", PermissionSet{}}, } { t.Run(tc.name, func(t *testing.T) { value, err := tc.set.Value() if err != nil { t.Fatal(err) } text := tc.set.Text() if tc.text == "" { if value != nil || text != nil { t.Fatalf("Value = %#v, Text = %v, want NULL", value, text) } } else if value != tc.text || text == nil || *text != tc.text { t.Fatalf("Value = %#v, Text = %v, want %s", value, text, tc.text) } var scanned PermissionSet if err := scanned.Scan(value); err != nil || !reflect.DeepEqual(scanned, tc.back) { t.Fatalf("Scan(Value) = %v %v, want %v", scanned, err, tc.back) } parsed, err := ParsePermissionSet([]byte(tc.text)) if err != nil || !reflect.DeepEqual(parsed, tc.back) { t.Fatalf("ParsePermissionSet(%q) = %v %v, want %v", tc.text, parsed, err, tc.back) } }) } if got := (PermissionSet{}).GormDataType(); got != "text" { t.Fatalf("GormDataType = %q", got) } } // TestParsePermissionSet: the tolerant read of what PHP may have stored, and // the error for content that is not a JSON object. func TestParsePermissionSet(t *testing.T) { for raw, want := range map[string]PermissionSet{ "": {}, " ": {}, "[]": {}, "null": {}, " {} ": {}, `{"a":1,"b":"1","c":" -1 "}`: {"a": 1, "b": 1, "c": -1}, // Values that are not integers are skipped, never read as granted. `{"a":true,"b":"yes","c":1.5,"d":null,"e":[1],"f":{"x":1},"g":1}`: {"g": 1}, `{"big":99999999999999999999}`: {}, } { got, err := ParsePermissionSet([]byte(raw)) if err != nil || got == nil || !reflect.DeepEqual(got, want) { t.Errorf("ParsePermissionSet(%q) = %v %v, want %v", raw, got, err, want) } } for _, raw := range []string{`{"a":1`, `["a"]`, `1`, `"a"`, `true`, `{"a":1}{"b":1}`, `{"a":1} x`} { if got, err := ParsePermissionSet([]byte(raw)); err == nil { t.Errorf("ParsePermissionSet(%q) = %v, want an error", raw, got) } } // Scan keeps the previous value on an error and takes text or bytes. set := PermissionSet{"kept": 1} if err := set.Scan(`["a"]`); err == nil || !reflect.DeepEqual(set, PermissionSet{"kept": 1}) { t.Fatalf("a failed Scan changed the set: %v %v", set, err) } if err := set.Scan([]byte(`{"a":-1}`)); err != nil || !reflect.DeepEqual(set, PermissionSet{"a": -1}) { t.Fatalf("Scan(bytes) = %v %v", set, err) } if err := set.Scan(nil); err != nil || set == nil || len(set) != 0 { t.Fatalf("Scan(nil) = %#v %v", set, err) } if err := set.Scan(3.5); err == nil { t.Fatal("Scan accepted a float") } }