Search code examples
kotlinmapkitkotlin-multiplatform

Crash when creating MKMapView in kotlin unit test


I'm trying to add tests to the part of my kotlin multiplatform library that uses Mapbox, but I am unable to instantiate an instance of MKMapView.

Even a test as simple as this crashes.

@Test
fun `test creating view`() {
    MKMapView(CGRectMake(0.0, 0.0, 512.0, 512.0))
}

The output is

2020-07-14 09:31:53.667 test.kexe[9090:10700111] Error creating notification handler for simulator graphics quality override: 3
2020-07-14 09:31:53.670 test.kexe[9090:10700111] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'contentScale is unreasonable (NaN or Inf)'
*** First throw call stack:
(
        0   CoreFoundation                      0x00007fff23e3cf0e __exceptionPreprocess + 350
        1   libobjc.A.dylib                     0x00007fff50ba89b2 objc_exception_throw + 48
        2   CoreFoundation                      0x00007fff23e3cad9 -[NSException raise] + 9
        3   VectorKit                           0x00007fff49c14143 _Z25checkForBogusContentScaled + 115
        4   VectorKit                           0x00007fff49c14252 -[VKMapView initShouldRasterize:inBackground:contentScale:auditToken:] + 62
        5   MapKit                              0x00007fff2782009a -[MKBasicMapView initWithFrame:andGlobe:shouldRasterize:] + 419
        6   MapKit                              0x00007fff27755b85 -[MKMapView _commonInitFromIB:gestureRecognizerHostView:showsAttribution:showsAppleLogo:] + 1331
        7   MapKit                              0x00007fff27756698 -[MKMapView initWithFrame:] + 253
        8   test.kexe                           0x000000010e346dd0 _70616e6765612d6170706c655f74657374_knbridge2 + 64
        9   test.kexe                           0x000000010e33fa8b kfun:com.weather.pangea.apple.AppleViewportTest.test creating view() + 987
        10  test.kexe                           0x000000010e3410a6 kfun:com.weather.pangea.apple.$AppleViewportTest$test$0.$test creating view$FUNCTION_REFERENCE$1.invoke#internal + 70
        11  test.kexe                           0x000000010e34111f kfun:com.weather.pangea.apple.$AppleViewportTest$test$0.$test creating view$FUNCTION_REFERENCE$1.$<bridge-UNNN>invoke(P1)#internal + 95
        12  test.kexe                           0x000000010e3e0fa7 kfun:kotlin.native.internal.test.BaseClassSuite.TestCase.run() + 1287
        13  test.kexe                           0x000000010e3d9256 kfun:kotlin.native.internal.test.TestRunner.run#internal + 2406
        14  test.kexe                           0x000000010e3da3e4 kfun:kotlin.native.internal.test.TestRunner.runIteration#internal + 2916
        15  test.kexe                           0x000000010e3dacee kfun:kotlin.native.internal.test.TestRunner.run()kotlin.Int + 958
        16  test.kexe                           0x000000010e3ce29d kfun:kotlin.native.internal.test.testLauncherEntryPoint(kotlin.Array<kotlin.String>)kotlin.Int + 301
        17  test.kexe                           0x000000010e3ce387 kfun:kotlin.native.internal.test.main(kotlin.Array<kotlin.String>) + 55
        18  test.kexe                           0x000000010e341315 Konan_start + 165
        19  test.kexe                           0x000000010e34ba1b Init_and_run_start + 107
        20  libdyld.dylib                       0x00007fff51a231fd start + 1

I am able to create the MKMapView correctly when running a real app on the Simulator. I'm guessing this is related to the environment that kotlin test uses to run the tests, but I have no clue how to configure that.

I'm using Kotlin 1.3.72 with the built in iOS test task for the gradle plugin.


Solution

  • The root cause here is that Kotlin/Native utilizes xcrun simctl spawn CLI tool for running tests. This command runs a given test on a simulator, not as an app but just as an executable file. This makes testing more straightforward, but some corner cases can work wrong. Probably, here we got an issue with device services responsible for graphics. In this assumption, I rely on 1) Error creating notification handler for simulator graphics quality override: 3 error message and 2) initShouldRasterize in the stacktrace, which seems suspicious to me.


    To prove that the problem is not directly related to Kotlin/Native, I've made two code snippets: map.swift and map.kt. Compiling each of them like: swiftc map.swift -sdk /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator13.5.sdk -target x86_64-apple-ios13.5 ~/.konan/kotlin-native-macos-1.3.72/bin/konanc -tr -g -ea map.kt -target ios_x64 -o map creates two executable files: map and map.kexe. After that, I run both of them using simctl spawn:

    xcrun simctl spawn -s "C01BDD64-19DC-49A0-9363-92EAFFD1B258" <absolute_path>/map
    2020-07-15 12:49:57.262 map[8840:1053205] Error creating notification handler for simulator graphics quality override: 3
    2020-07-15 12:49:57.264 map[8840:1053205] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'contentScale is unreasonable (NaN or Inf)'
    *** First throw call stack:
    (
        0   CoreFoundation                      0x00007fff23e3cf0e __exceptionPreprocess + 350
        1   libobjc.A.dylib                     0x00007fff50ba89b2 objc_exception_throw + 48
        2   CoreFoundation                      0x00007fff23e3cad9 -[NSException raise] + 9
        3   VectorKit                           0x00007fff49c14143 _Z25checkForBogusContentScaled + 115
        4   VectorKit                           0x00007fff49c14252 -[VKMapView initShouldRasterize:inBackground:contentScale:auditToken:] + 62
        5   MapKit                              0x00007fff2782009a -[MKBasicMapView initWithFrame:andGlobe:shouldRasterize:] + 419
        6   MapKit                              0x00007fff27755b85 -[MKMapView _commonInitFromIB:gestureRecognizerHostView:showsAttribution:showsAppleLogo:] + 1331
        7   MapKit                              0x00007fff27756698 -[MKMapView initWithFrame:] + 253
        8   map                                 0x000000010b924f0d $sSo9MKMapViewC5frameABSo6CGRectV_tcfcTO + 77
        9   map                                 0x000000010b924eaa $sSo9MKMapViewC5frameABSo6CGRectV_tcfC + 74
        10  map                                 0x000000010b924e07 main + 183
        11  libdyld.dylib                       0x00007fff51a231fd start + 1
    )
    libc++abi.dylib: terminating with uncaught exception of type NSException
    Child process terminated with signal 6: Abort trap
    
    xcrun simctl spawn -s "C01BDD64-19DC-49A0-9363-92EAFFD1B258" <absolute_path>/map.kexe
    [==========] Running 1 tests from 1 test cases.
    [----------] Global test environment set-up.
    [----------] 1 tests from MapKt
    [ RUN      ] MapKt.test creating view
    2020-07-15 13:49:19.079 map.kexe[9117:1072135] Error creating notification handler for simulator graphics quality override: 3
    2020-07-15 13:49:19.082 map.kexe[9117:1072135] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'contentScale is unreasonable (NaN or Inf)'
    *** First throw call stack:
    (
        0   CoreFoundation                      0x00007fff23e3cf0e __exceptionPreprocess + 350
        1   libobjc.A.dylib                     0x00007fff50ba89b2 objc_exception_throw + 48
        2   CoreFoundation                      0x00007fff23e3cad9 -[NSException raise] + 9
        3   VectorKit                           0x00007fff49c14143 _Z25checkForBogusContentScaled + 115
        4   VectorKit                           0x00007fff49c14252 -[VKMapView initShouldRasterize:inBackground:contentScale:auditToken:] + 62
        5   MapKit                              0x00007fff2782009a -[MKBasicMapView initWithFrame:andGlobe:shouldRasterize:] + 419
        6   MapKit                              0x00007fff27755b85 -[MKMapView _commonInitFromIB:gestureRecognizerHostView:showsAttribution:showsAppleLogo:] + 1331
        7   MapKit                              0x00007fff27756698 -[MKMapView initWithFrame:] + 253
        8   map.kexe                            0x000000010e29c530 _6d6170_knbridge0 + 64
        9   map.kexe                            0x000000010e293605 kfun:test creating view() + 1077
        10  map.kexe                            0x000000010e2938f5 kfun:$test creating view$FUNCTION_REFERENCE$0.invoke#internal + 37
        11  map.kexe                            0x000000010e29394e kfun:$test creating view$FUNCTION_REFERENCE$0.$<bridge-UNN>invoke()#internal + 62
        12  map.kexe                            0x000000010e206218 kfun:kotlin.native.internal.test.TopLevelSuite.TestCase.run() + 1112
        13  map.kexe                            0x000000010e1fe73d kfun:kotlin.native.internal.test.TestRunner.run#internal + 2445
        14  map.kexe                            0x000000010e1ff8ea kfun:kotlin.native.internal.test.TestRunner.runIteration#internal + 2954
        15  map.kexe                            0x000000010e200215 kfun:kotlin.native.internal.test.TestRunner.run()kotlin.Int + 997
        16  map.kexe                            0x000000010e1f3826 kfun:kotlin.native.internal.test.testLauncherEntryPoint(kotlin.Array<kotlin.String>)kotlin.Int + 310
        17  map.kexe                            0x000000010e1f36ca kfun:kotlin.native.internal.test.main(kotlin.Array<kotlin.String>) + 58
        18  map.kexe                            0x000000010e1f3975 Konan_start + 165
        19  map.kexe                            0x000000010e2a13ab Init_and_run_start + 107
        20  libdyld.dylib                       0x00007fff51a231fd start + 1
        21  ???                                 0x0000000000000001 0x0 + 1
    )
    libc++abi.dylib: terminating with uncaught exception of type NSException
    Child process terminated with signal 6: Abort trap
    

    Nevertheless, I would agree that this inconvenience should be solved to make testing more user-friendly. I can file an issue at the Kotlin bug tracker, are you okay with that?