This allows writing tests for TokamakStaticHTML, TokamakDOM, and TokamakGTK targets.
The issue was caused by conflicting ViewDeferredToRenderer conformances declared in different modules, including the TokamakTestRenderer module.
This works around a general limitation in Swift, which was discussed at length on Swift Forums previously. When multiple conflicting conformances to the same protocol (ViewDeferredToRenderer in our case) exist in different modules, only one of them is available in a given binary (even a test binary). Also, only of them can be loaded and used. Which one exactly is loaded can't be known at compile-time, which is hard to debug and leads to breaking tests that cover code in different renderers. We had to disable TokamakStaticHTMLTests for this reason.
The workaround is to declare two new functions in the Renderer protocol:
public protocol Renderer: AnyObject {
// ...
// Functions unrelated to the issue at hand skipped for brevity.
/** Returns a body of a given pritimive view, or `nil` if `view` is not a primitive view for
this renderer.
*/
func body(for view: Any) -> AnyView?
/** Returns `true` if a given view type is a primitive view that should be deferred to this
renderer.
*/
func isPrimitiveView(_ type: Any.Type) -> Bool
}
Now each renderer can declare their own protocols for their primitive views, i.e. HTMLPrimitive, DOMPrimitive, GTKPrimitive etc, delegating to them from the implementations of body(for view:) and isPrimitiveView(_:). Conformances to these protocols can't conflict across different modules. Also, these protocols can have internal visibility, as opposed to ViewDeferredToRenderer, which had to be declared as public in TokamakCore to be visible in renderer modules.
This allows writing tests for
TokamakStaticHTML
,TokamakDOM
, andTokamakGTK
targets.The issue was caused by conflicting
ViewDeferredToRenderer
conformances declared in different modules, including theTokamakTestRenderer
module.This works around a general limitation in Swift, which was discussed at length on Swift Forums previously. When multiple conflicting conformances to the same protocol (
ViewDeferredToRenderer
in our case) exist in different modules, only one of them is available in a given binary (even a test binary). Also, only of them can be loaded and used. Which one exactly is loaded can't be known at compile-time, which is hard to debug and leads to breaking tests that cover code in different renderers. We had to disableTokamakStaticHTMLTests
for this reason.The workaround is to declare two new functions in the
Renderer
protocol:Now each renderer can declare their own protocols for their primitive views, i.e.
HTMLPrimitive
,DOMPrimitive
,GTKPrimitive
etc, delegating to them from the implementations ofbody(for view:)
andisPrimitiveView(_:)
. Conformances to these protocols can't conflict across different modules. Also, these protocols can haveinternal
visibility, as opposed toViewDeferredToRenderer
, which had to be declared aspublic
inTokamakCore
to be visible in renderer modules.