Skip to content

Commit

Permalink
Project import generated by Copybara.
Browse files Browse the repository at this point in the history
FolderOrigin-RevId: /usr/local/google/home/gdennis/copybara/temp/folder-destination13746584620581184573/.
  • Loading branch information
GGN Engprod Team authored and greg-dennis committed Sep 21, 2023
1 parent b1ff123 commit 52f46fa
Show file tree
Hide file tree
Showing 5 changed files with 49,439 additions and 47,244 deletions.
75 changes: 75 additions & 0 deletions binding/as.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package binding

import (
"fmt"
"reflect"
)

// DUTAs tests if the specified DUT or any DUT it transitively embeds fulfills
// the interface pointed to by target, and if so, sets target to that DUT.
func DUTAs(dut DUT, target any) error {
return as(dut, target, "DUT", func(v any) (DUT, bool) {
d, ok := v.(DUT)
return d, ok
})
}

// ATEAs tests if the specified ATE or any ATE it transitively embeds fulfills
// the interface pointed to by target, and if so, sets target to that ATE.
func ATEAs(ate ATE, target any) error {
return as(ate, target, "ATE", func(v any) (ATE, bool) {
d, ok := v.(ATE)
return d, ok
})
}

func as[T Device](src T, target any, field string, assert func(any) (T, bool)) error {
targetPtrVal, ok := nonNilPtr(target)
if !ok {
return fmt.Errorf("target must be non-nil pointer, got %v (%T)", target, target)
}
targetVal := targetPtrVal.Elem()

for {
srcVal, ok := nonNilPtr(src)
if !ok {
return fmt.Errorf("src must be non-nil pointer, got %v (%T)", src, src)
}
if srcVal.Type().AssignableTo(targetVal.Type()) {
targetVal.Set(srcVal)
return nil
}
embedField := srcVal.Elem().FieldByName(field)
if !embedField.IsValid() {
return fmt.Errorf("no match found")
}
intf := embedField.Interface()
if intf == nil {
return fmt.Errorf("no match found")
}
src, ok = assert(intf)
if !ok {
return fmt.Errorf("embedded field %v must be a %v", embedField, field)
}
}
}

func nonNilPtr(v any) (reflect.Value, bool) {
val := reflect.ValueOf(v)
ok := val.IsValid() && val.Type().Kind() == reflect.Ptr && !val.IsNil()
return val, ok
}
198 changes: 198 additions & 0 deletions binding/as_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package binding

import (
"strings"
"testing"
)

var target interface {
testFunc()
}

func TestDUTAs(t *testing.T) {
tests := []struct {
desc string
fn func() error
wantErr string
}{{
desc: "target nil",
fn: func() error {
return DUTAs(&testDUT{}, nil)
},
wantErr: "target must",
}, {
desc: "target non-pointer",
fn: func() error {
return DUTAs(&testDUT{}, testDUT{})
},
wantErr: "target must",
}, {
desc: "src nil",
fn: func() error {
return DUTAs(nil, &target)
},
wantErr: "src must",
}, {
desc: "src non-pointer",
fn: func() error {
return DUTAs(wrapDUT{}, &target)
},
wantErr: "src must",
}, {
desc: "no match",
fn: func() error {
return DUTAs(&wrapDUT{}, &target)
},
wantErr: "no match",
}, {
desc: "no match - wrapped",
fn: func() error {
return DUTAs(&wrapDUT{&AbstractDUT{}}, &target)
},
wantErr: "no match",
}, {
desc: "wrong embed type",
fn: func() error {
return DUTAs(&struct {
*AbstractDUT
DUT string
}{
AbstractDUT: &AbstractDUT{},
}, &target)
},
wantErr: "embedded field",
}, {
desc: "match",
fn: func() error {
return DUTAs(&testDUT{}, &target)
},
}, {
desc: "match - wrapped",
fn: func() error {
return DUTAs(&wrapDUT{&testDUT{}}, &target)
},
}}
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
target = nil
gotErr := test.fn()
if (gotErr == nil) != (test.wantErr == "") || (gotErr != nil && !strings.Contains(gotErr.Error(), test.wantErr)) {
t.Errorf("DUTAs() got err %v, want err %v", gotErr, test.wantErr)
}
if gotTarget, wantTarget := target != nil, test.wantErr == ""; gotTarget != wantTarget {
t.Errorf("DUTAs() got target? %v, want target? %v", gotTarget, wantTarget)
}
})
}
}

type wrapDUT struct {
DUT
}

type testDUT struct {
DUT
}

func (*testDUT) testFunc() {}

func TestATEAs(t *testing.T) {
tests := []struct {
desc string
fn func() error
wantErr string
}{{
desc: "target nil",
fn: func() error {
return ATEAs(&testATE{}, nil)
},
wantErr: "target",
}, {
desc: "target non-pointer",
fn: func() error {
return ATEAs(&testATE{}, testATE{})
},
wantErr: "target must",
}, {
desc: "src nil",
fn: func() error {
return ATEAs(nil, &target)
},
wantErr: "src must",
}, {
desc: "src non-pointer",
fn: func() error {
return ATEAs(wrapATE{}, &target)
},
wantErr: "src must",
}, {
desc: "no match",
fn: func() error {
return ATEAs(&wrapATE{}, &target)
},
wantErr: "no match",
}, {
desc: "no match - wrapped",
fn: func() error {
return ATEAs(&wrapATE{&AbstractATE{}}, &target)
},
wantErr: "no match",
}, {
desc: "wrong embed type",
fn: func() error {
return ATEAs(&struct {
*AbstractATE
ATE string
}{
AbstractATE: &AbstractATE{},
}, &target)
},
wantErr: "embedded field",
}, {
desc: "match",
fn: func() error {
return ATEAs(&testATE{}, &target)
},
}, {
desc: "match - wrapped",
fn: func() error {
return ATEAs(&wrapATE{&testATE{}}, &target)
},
}}
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
target = nil
gotErr := test.fn()
if (gotErr == nil) != (test.wantErr == "") || (gotErr != nil && !strings.Contains(gotErr.Error(), test.wantErr)) {
t.Errorf("ATEAs() got err %v, want err %v", gotErr, test.wantErr)
}
if gotTarget, wantTarget := target != nil, test.wantErr == ""; gotTarget != wantTarget {
t.Errorf("ATEAs() got target? %v, want target? %v", gotTarget, wantTarget)
}
})
}
}

type wrapATE struct {
ATE
}

type testATE struct {
ATE
}

func (*testATE) testFunc() {}
Loading

0 comments on commit 52f46fa

Please sign in to comment.