Closed lexidor closed 1 year ago
Intriguing proposal, thanks for writing it up!
I'll think about it some more, but some initial impressions:
$this->testMap(...)
), so someone could accidentally put something else there (call to a different test function, or something completely different), resulting in an invalid test, confusing output, etc.final class MyTestClass extends HackTest {
public function testMap1(): void {
$this->testMap(Vec\range(10, 15), $x ==> $x * 2, vec[20, 22, 24, 26, 28, 30]);
}
public function testMap2(): void {
$this->testMap(varray['a'], $x ==> $x. ' buzz', vec['a buzz']);
}
public function testMap<Tv1, Tv2>(
Traversable<Tv1> $traversable,
(function(Tv1): Tv2) $value_func,
vec<Tv2> $expected,
): void {
expect(Vec\map($traversable, $value_func))->toEqual($expected);
}
}
Is there a good case for using the proposed version instead of just doing something like this?
That would work nicely too.
How would this prevent you from calling $this->someOtherTestFunction()
in testMap2()
.
Especially when there are multiple testcases in testMap2().
You could prevent people from making that mistake using __FUNCTION_CREDENTIAL__
.
HackTest would just have to assert that they are all the same.
final class MyTestClass extends HackTest {
<<TestBatchProvider>>
public function provideTestMap(): vec<(function(): FunctionCredential)> {
return vec[
() ==> $this->testMap(/*...*/),
() ==> $this->testMap(/*...*/)
];
}
public function testMap<Tv1, Tv2>(/*...*/): FunctionCredential {
expect(Vec\map($traversable, $value_func))->toEqual($expected);
return __FUNCTION_CREDENTIAL__;
}
}
There is nothing meaningful that HackTest could do that a simple Vec\map_async()
over the tests in provideTestMap()
couldn't do. Closing...
Context
There is currently no typesafe way to write this kind of test (hhvm/hsl/tests/vec/VecTranformTest.php):
The real return type of provideTestMap is
vec<(Traversable<T1>, (function(T): T2), T2)>
, which Hack should infer asvec<(Traversable<arraykey>, (function(arraykey): arraykey), arraykey)>
. However, the first method operates on ints, not strings, so putting the real return type in the method signature will cause a hh_client error. Vecs can't have a different (rebound) generic for each element, so we must provide a better way of providing the results, which can rebind the generics for each element.I am not at all bound to this suggestion, but this could be something that works.
This is more clunky than returning tuples, but it pushes the typesafety into the Hack typesystem, instead of into a linter.
I'd be willing to work on this myself. One thing however, how do we prevent HackTest from still trying to execute
testMap()
?