如何在 Cuis/Squeak/Pharo 中实现实例行为(用于测试)?

How to implement instance behaviour (for testing) in Cuis/Squeak/Pharo?

我已经实现了一些 ExternalStrctures(作为 "FFI effort" 的一部分),对于其中一些我想实现最终确定以回收外部内存。

我正在尝试为此编写一些测试,并且认为了解 #finalize 是否被调用的一个好方法是更改​​我用于测试的特定实例的行为。如果可能的话,我宁愿不使用支持测试的代码来污染实现。

我认为模拟特定方法和更改特定实例行为通常是一个很好的测试工具。

我知道这在其他方言中是可行的,并且我过去在 Squeak 中使用 #doesNotUnderstand 自己实现了它,但我想知道是否有更简洁的方法,可能由 VM 支持.

有没有办法改变特定实例在 Cuis/Squeak/Pharo 中回复特定消息的方式?

Luciano 给出了这个精彩的例子:

EllipseMorph 复制编译:'defaultColor ^Color red';新:: openInWorld

邮件线程在这里: http://cuis-smalltalk.org/pipermail/cuis-dev_cuis-smalltalk.org/2016-March/000458.html

解决问题后我决定进行端到端测试,实际验证资源(在我的例子中是内存)是否已恢复到系统。我没有使用实例行为,尽管 Luciano 和 Juan 的解决方案(在评论中)非常有趣。这是我用于测试的代码:

testFinalizationReleasesExternalMemory
    " WeakArray restartFinalizationProcess "
    | handles |

    handles := (1 to: 11) collect: [:i |
        Smalltalk garbageCollect.
        APIStatus create getHandle].

    self assert: (handles asSet size) < 11.

在示例中,#create 使用 FFI 调用分配内存的外部函数和 returns 指针(名称 create 来自外部 API ):

create
    | answer |
    answer := ExternalAPI current createStatus.
    self finalizationRegistry add: answer.
    ^ answer

ExternalAPI 这里是 FFI 接口,#createStatus 是 API 调用,为 APIStatus 和 returns 指针分配内存.

完成后,我调用 API 来恢复内存:

delete
    self finalizationRegistry remove: self ifAbsent: [].
    self library deleteStatus: self.
    handle := nil.

其中 #deleteStatus: 又是释放内存的 API 调用。

测试假定外部库在内存空闲后重新使用内存,特别是当新分配的块与前一个块大小相同时。这在今天的大多数情况下都是正确的,但如果不是,我希望看到这个测试失败,至少只是为了学习一些新东西。

测试分配了 11 个外部结构,保存它们的指针,在分配下一个之前让终止机制释放每个结构的内存,然后比较是否有任何指针重复。我不确定为什么我决定使用 10 个指针作为一个好的数字,只要 2 个就足够了,但内存分配算法有时很棘手。