深度相等性用于ssh.AuthMethod。

huangapple go评论89阅读模式
英文:

(go) Deep equality for ssh.AuthMethod

问题

我正在使用 crypto/ssh 包,并且我正在尝试为构建 ClientConfig 的方法编写单元测试。

其中一个单元测试的断言是返回的 ClientConfig 与预期的值深度相等。
断言失败是因为 ClientConfigAuthHostKeyCallback 字段都不是深度相等的。
HostKeyCallback 被硬编码为 ssh.InsecureIgnoreHostKey()
目前我正在测试的唯一身份验证方法是使用密码,并且我已经验证了密码字符串被正确地获取。

我在 playground 中尝试了一些操作(参见这里),但我不明白为什么在这些情况下没有深度相等。

package main

import (
	"fmt"
	"reflect"

	"golang.org/x/crypto/ssh"
)

func main() {
	pass := "bar"
	auth := []ssh.AuthMethod{ssh.Password(pass)}
	authLiteral := []ssh.AuthMethod{ssh.Password("bar")}
	if reflect.DeepEqual(authLiteral, auth) {
		fmt.Println("authentication methods are equal")
	} else {
		fmt.Println("authentication methods are not equal")
	}

	callback1 := ssh.InsecureIgnoreHostKey()
	callback2 := ssh.InsecureIgnoreHostKey()
	if reflect.DeepEqual(callback1, callback2) {
		fmt.Println("callbacks are equal")
	} else {
		fmt.Println("callbacks are not equal")
	}
}
authentication methods are not equal
callbacks are not equal

请问有人可以解释一下这些结果吗?
如果可能的话,我也很感激您能提供如何对这种情况进行单元测试的建议。

英文:

I'm using crypto/ssh package and I'm trying to write a unit test for a method that constructs the ClientConfig.

One of the assertions in the unit is that the returned ClientConfig is deeply equal to the expected.
The assertion fails because both Auth and HostKeyCallback fields of ClientConfig are not deeply equal.
The HostKeyCallback is hardcoded to be ssh.InsecureIgnoreHostKey().
The only authentication method I'm testing right now is with password and I have verified that the password string is picked up correctly.

I tried to mess around in playground (see here) and I don't understand why there is no deep equality in these cases.

package main

import (
	"fmt"
	"reflect"

	"golang.org/x/crypto/ssh"
)

func main() {
	pass := "bar"
	auth := []ssh.AuthMethod{ssh.Password(pass)}
	authLiteral := []ssh.AuthMethod{ssh.Password("bar")}
	if reflect.DeepEqual(authLiteral, auth) {
		fmt.Println("authentication methods are equal")
	} else {
		fmt.Println("authentication methods are not equal")
	}

	callback1 := ssh.InsecureIgnoreHostKey()
	callback2 := ssh.InsecureIgnoreHostKey()
	if reflect.DeepEqual(callback1, callback2) {
		fmt.Println("callbacks are equal")
	} else {
		fmt.Println("callbacks are not equal")
	}
}
authentication methods are not equal
callbacks are not equal

Could someone please explain these results?
I would also be grateful if you could suggest how I could unit test this case.

答案1

得分: 0

正如mkopriva在评论中指出的,这在形式上是不允许的。(不过,如果reflect.DeepEqual(Go实现中自带的)能像下面我所做的那样做些什么就好了。因为它是与实现一起提供的,实现者可以使用特殊的知识来编写它。)

当然,最终,对于指向以T<sub>1</sub>,T<sub>2</sub>,... T<sub>na</sub>为参数类型,返回类型为R<sub>1</sub>,R<sub>2</sub>,... R<sub>nr</sub>的函数指针的机器级实现是存在的。但我们并没有被告知这个表示是什么*。它可能是一个单独的unsafe.Pointer值,或者它可能是某种内联展开的thunk。所以我们不知道在这里要比较多少字节。

如果你愿意做一些相当危险/不可移植的假设,并在它们被证明不足时进行更新,这里确实有一种“作弊”的方法。我在Go Playground上制作了这个示例,它产生了期望的输出。这只是偶然的吗,还是这在你的Go实现上真的有效?

以下是代码的文本版本。请自行承担风险!

package main

import (
	"fmt"
	"unsafe"
)

func dummy1() {}
func dummy2() {}

func main() {
	fmt.Println("dummy1 == dummy2 =>", qe(dummy1, dummy2))
	fmt.Println("dummy1 == dummy1 =>", qe(dummy1, dummy1))
}

// "questionably equal", for function pointers
func qe(a, b func()) bool {
	pp1 := (*unsafe.Pointer)(unsafe.Pointer(&a))
	pp2 := (*unsafe.Pointer)(unsafe.Pointer(&b))
	p1 := *pp1
	p2 := *pp2
	return p1 == p2
}
英文:

As mkopriva notes in a comment, this is formally disallowed. (Still, it might be nice if reflect.DeepEqual, which comes with the Go implementation, did something like I did below. Because it comes with the implementation, the implementor can use special knowledge to write it.)

Ultimately, of course, there's some machine-level implementation for pointer to function taking arguments of types T<sub>1</sub>, T<sub>2</sub>, ... T<sub>na</sub> and returning values value of types R<sub>1</sub>, R<sub>2</sub>, ... R<sub>nr</sub>&nbsp;. But we're not told what that representation is. It might be a single unsafe.Pointer value, or it might be some kind of inline expansion of a thunk. So we don't know how many bytes to compare here.

If you're willing to make rather dangerous / non-portable assumptions, and update them if and when they prove inadequate, there is a way to "cheat" here. I made this example on the Go Playground, which produces the desired output. Is this just by chance, or does this really work on your Go implementation?

The text is also below. Use at your own risk!

package main

import (
	&quot;fmt&quot;
	&quot;unsafe&quot;
)

func dummy1() {}
func dummy2() {}

func main() {
	fmt.Println(&quot;dummy1 == dummy2 =&gt;&quot;, qe(dummy1, dummy2))
	fmt.Println(&quot;dummy1 == dummy1 =&gt;&quot;, qe(dummy1, dummy1))
}

// &quot;questionably equal&quot;, for function pointers
func qe(a, b func()) bool {
	pp1 := (*unsafe.Pointer)(unsafe.Pointer(&amp;a))
	pp2 := (*unsafe.Pointer)(unsafe.Pointer(&amp;b))
	p1 := *pp1
	p2 := *pp2
	return p1 == p2
}

huangapple
  • 本文由 发表于 2022年4月2日 18:01:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/71716551.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定