Xcodeのカバレッジ計測ではなぜブランチカバレッジが取れないのだろうか?

Aaf94d61dec57d1c3cf2de7c09e472d4?s=47 Daiki Katayama
September 06, 2019

 Xcodeのカバレッジ計測ではなぜブランチカバレッジが取れないのだろうか?

Aaf94d61dec57d1c3cf2de7c09e472d4?s=128

Daiki Katayama

September 06, 2019
Tweet

Transcript

  1. 18.

    /Users/daiki/workspace/sandbox/MVP_ConnpassEventSearch/MVP_ConnpassEventSearch/ MVP_ConnpassEventSearch/AppDelegate.swift 48.15% (13/27) MVP_ConnpassEventSearch.AppDelegate.application(_: __C.UIApplication, didFinishLaunchingWithOptions: Swift.Optional<Swift.Dictionary<__C.UIApplicationLaunchOptionsKey, Any>>) ->

    Swift.Bool 100.00% (10/10) MVP_ConnpassEventSearch.AppDelegate.applicationWillResignActive(__C.UIApplication) -> () 0.00% (0/4) MVP_ConnpassEventSearch.AppDelegate.applicationDidEnterBackground(__C.UIApplication) -> () 0.00% (0/4) MVP_ConnpassEventSearch.AppDelegate.applicationWillEnterForeground(__C.UIApplication) -> () 0.00% (0/3) MVP_ConnpassEventSearch.AppDelegate.applicationDidBecomeActive(__C.UIApplication) -> () 100.00% (3/3) MVP_ConnpassEventSearch.AppDelegate.applicationWillTerminate(__C.UIApplication) -> () 18
  2. 31.

    main.swift let number = 10 if number % 2 ==

    0 { print("ۮ਺") } ୯७ͳϓϩάϥϜͰܭଌͯ͠ΈΔ 31
  3. 40.

    "totals": { "lines": { "count": 3, "covered": 3, "percent": 100

    }, "functions": { "count": 2, "covered": 2, "percent": 100 }, "instantiations": { "count": 2, "covered": 2, "percent": 100 }, "regions": { "count": 4, "covered": 4, "notcovered": 0, "percent": 100 } } llvm-covͰग़ྗͨ͠
 JSONͷҰ෦ • lines • functions • Instantiations • regions 40
  4. 45.

    let result = 10 % 2 == 0 ? true

    : false 1ߦ͚ͩͷ؆୯ͳίʔυͷΧόϨοδΛݟͯΈΔ 45
  5. 54.

    struct Foo { func bar() { let number = 10

    if number % 2 == 0 || number == 10 { print("ۮ਺Ͱ10") } } } 54
  6. 55.

    struct Foo { func bar() { let number = 10

    if number % 2 == 0 || number == 10 { print("ۮ਺Ͱ10") } } } struct Coverage { func hhoge() { let number = 10 if number % 2 == 0 || number == 10 { print("ۮ਺Ͱ10") } } } 55
  7. 57.

    public static func || (lhs: Bool, rhs: @autoclosure () throws

    -> Bool) rethrows -> Bool { return lhs ? true : try rhs() } Swiftͷ࣮૷ͱͯ͠&&΍||ͷӈล͸closureͱͯ͠ ॲཧ͞ΕΔ 57
  8. 59.

    • Source-based Code Coverage͸LLVM͕ఏڙ ͢ΔCode Coverage Mapping Formatͱ͍͏ ΋ͷΛར༻ͯ͠ܭଌ͍ͯ͠Δ •

    ΦϓγϣϯΛ͚ͭͯίϯύΠϧͨ͠ࡍʹ Ϛοϐϯά༻ͷσʔλ͕ຒΊࠐ·ΕΔ 59
  9. 66.

    @"__profc_Coverage/Coverage.swift:$S4Hoge3FooV3baryyF" = linkonce hidden global [2 x i64] zeroinitializer, section

    "__DATA,__llvm_prf_cnts", align 8 @"__profd_Coverage/Coverage.swift:$S4Hoge3FooV3baryyF" = linkonce hidden global { i64, i64, i64*, i8*, i8*, i32, [2 x i16] } { i64 1740746221156547191, i64 0, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/Coverage.swift:$S4Hoge3FooV3baryyF", i32 0, i32 0), i8* bitcast (void ()* @"$S4Hoge3FooV3baryyF" to i8*), i8* null, i32 2, [2 x i16] zeroinitializer }, section "__DATA,__llvm_prf_data,regular,live_support", align 8 @"__profc_Coverage/Coverage.swift:__ntd_Foo_line:1:1" = linkonce hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 @"__profd_Coverage/Coverage.swift:__ntd_Foo_line:1:1" = linkonce hidden global { i64, i64, i64*, i8*, i8*, i32, [2 x i16] } { i64 -7581103708217037269, i64 0, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @"__profc_Coverage/Coverage.swift:__ntd_Foo_line:1:1", i32 0, i32 0), i8* bitcast (void ()* @"$S4Hoge3FooVACycfC" to i8*), i8* null, i32 1, [2 x i16] zeroinitializer }, section "__DATA,__llvm_prf_data,regular,live_support", align 8 @"__profc_Coverage/Coverage.swift:$S4Hoge3FooV3baryyFSbyKXKfu_" = linkonce hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 @"__profd_Coverage/Coverage.swift:$S4Hoge3FooV3baryyFSbyKXKfu_" = linkonce hidden global { i64, i64, i64*, i8*, i8*, i32, [2 x i16] } { i64 3556985279047318519, i64 0, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @"__profc_Coverage/Coverage.swift:$S4Hoge3FooV3baryyFSbyKXKfu_", i32 0, i32 0), i8* bitcast (void ()* @"$S4Hoge3FooV3baryyF" to i8*), i8* null, i32 1, [2 x i16] zeroinitializer }, section "__DATA,__llvm_prf_data,regular,live_support", align 8 ϔομʔ෦෼ͷҰ෦ʹ஫໨ 66
  10. 68.

    @"__profc_Coverage/Coverage.swift:Hoge.Foo.bar() -> () @"__profc_Coverage/Coverage.swift:__ntd_Foo_line:1:1" @"__profc_Coverage/Coverage.swift:implicit closure #1 : @autoclosure ()

    throws -> Swift.Bool in Hoge.Foo.bar() -> () @"__profc_Coverage/Coverage.swift:$S4Hoge3FooV3baryyF" @"__profc_Coverage/Coverage.swift:__ntd_Foo_line:1:1" @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyFSbyKXKfu_" 68
  11. 70.

    define hidden swiftcc void @"$S4Hoge3FooV3baryyF"() #0 { entry: %pgocount =

    load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyF", i64 0, i64 0) %0 = add i64 %pgocount, 1 store i64 %0, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyF", i64 0, i64 0) br label %1 70
  12. 71.

    define hidden swiftcc void @"$S4Hoge3FooV3baryyF"() #0 { entry: %pgocount =

    load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyF", i64 0, i64 0) %0 = add i64 %pgocount, 1 store i64 %0, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyF", i64 0, i64 0) br label %1 define hidden swiftcc void @"$S4Hoge3FooV3baryyF"() #0 { entry: %pgocount = load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyF", i64 0, i64 0) %0 = add i64 %pgocount, 1 store i64 %0, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyF", i64 0, i64 0) br label %1 71
  13. 72.

    define hidden swiftcc void @"$S4Hoge3FooV3baryyF"() #0 { entry: %pgocount =

    load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyF", i64 0, i64 0) %0 = add i64 %pgocount, 1 store i64 %0, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyF", i64 0, i64 0) br label %1 define hidden swiftcc void @"$S4Hoge3FooV3baryyF"() #0 { entry: %pgocount = load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyF", i64 0, i64 0) %0 = add i64 %pgocount, 1 store i64 %0, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyF", i64 0, i64 0) br label %1 ઌ΄ͲσϚϯάϧͨ͠ΒҎԼʹͳͬͨ΋ͷ @"__profc_Coverage/Coverage.swift:Hoge.Foo.bar() -> () 72
  14. 74.

    define hidden swiftcc void @"$S4Hoge3FooV3baryyF"() #0 { entry: %pgocount =

    load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyF", i64 0, i64 0) %0 = add i64 %pgocount, 1 store i64 %0, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyF", i64 0, i64 0) br label %1 define hidden swiftcc void @"$S4Hoge3FooV3baryyF"() #0 { entry: %pgocount = load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyF", i64 0, i64 0) %0 = add i64 %pgocount, 1 store i64 %0, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyF", i64 0, i64 0) br label %1 ͔͜͜ΒFoo.bar()ͷελʔτ 74
  15. 75.

    define hidden swiftcc void @"$S4Hoge3FooV3baryyF"() #0 { entry: %pgocount =

    load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyF", i64 0, i64 0) %0 = add i64 %pgocount, 1 store i64 %0, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyF", i64 0, i64 0) br label %1 define hidden swiftcc void @"$S4Hoge3FooV3baryyF"() #0 { entry: %pgocount = load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyF", i64 0, i64 0) %0 = add i64 %pgocount, 1 store i64 %0, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyF", i64 0, i64 0) br label %1 άϩʔόϧม਺(഑ྻ)͔ΒཁૉΛऔΓग़ͯ͠ɺ ϨδελpgocountೖΕ͍ͯΔ 75
  16. 76.

    define hidden swiftcc void @"$S4Hoge3FooV3baryyF"() #0 { entry: %pgocount =

    load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyF", i64 0, i64 0) %0 = add i64 %pgocount, 1 store i64 %0, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyF", i64 0, i64 0) br label %1 define hidden swiftcc void @"$S4Hoge3FooV3baryyF"() #0 { entry: %pgocount = load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyF", i64 0, i64 0) %0 = add i64 %pgocount, 1 store i64 %0, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyF", i64 0, i64 0) br label %1 pgocountͱ1ΛՃࢉͯ͠Ϩδελ0ʹೖΕ͍ͯΔ 76
  17. 77.

    define hidden swiftcc void @"$S4Hoge3FooV3baryyF"() #0 { entry: %pgocount =

    load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyF", i64 0, i64 0) %0 = add i64 %pgocount, 1 store i64 %0, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyF", i64 0, i64 0) br label %1 define hidden swiftcc void @"$S4Hoge3FooV3baryyF"() #0 { entry: %pgocount = load i64, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyF", i64 0, i64 0) %0 = add i64 %pgocount, 1 store i64 %0, i64* getelementptr inbounds ([2 x i64], [2 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyF", i64 0, i64 0) br label %1 ܭࢉ݁ՌͷϨδελ0Λάϩʔόϧม਺ʹอଘ 77
  18. 79.

    ; <label>:3: ; preds = %2 br i1 true, label

    %4, label %7 ͨͩͷ෼ذ 79
  19. 80.

    ; <label>:7: ; preds = %3 %pgocount1 = load i64,

    i64* getelementptr inbounds ([1 x i64], [1 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyFSbyKXKfu_", i64 0, i64 0) %8 = add i64 %pgocount1, 1 store i64 %8, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyFSbyKXKfu_", i64 0, i64 0) br label %9 80
  20. 81.

    ; <label>:7: ; preds = %3 %pgocount1 = load i64,

    i64* getelementptr inbounds ([1 x i64], [1 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyFSbyKXKfu_", i64 0, i64 0) %8 = add i64 %pgocount1, 1 store i64 %8, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyFSbyKXKfu_", i64 0, i64 0) br label %9 ; <label>:7: ; preds = %3 %pgocount1 = load i64, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyFSbyKXKfu_", i64 0, i64 0) %8 = add i64 %pgocount1, 1 store i64 %8, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyFSbyKXKfu_", i64 0, i64 0) br label %9 81
  21. 82.

    ; <label>:7: ; preds = %3 %pgocount1 = load i64,

    i64* getelementptr inbounds ([1 x i64], [1 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyFSbyKXKfu_", i64 0, i64 0) %8 = add i64 %pgocount1, 1 store i64 %8, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyFSbyKXKfu_", i64 0, i64 0) br label %9 ; <label>:7: ; preds = %3 %pgocount1 = load i64, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyFSbyKXKfu_", i64 0, i64 0) %8 = add i64 %pgocount1, 1 store i64 %8, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyFSbyKXKfu_", i64 0, i64 0) br label %9 ઌ΄ͲσϚϯάϧͨ͠ΒҎԼʹͳͬͨ΋ͷ @"__profc_Coverage/Coverage.swift:implicit closure #1 : @autoclosure () throws -> Swift.Bool in Hoge.Foo.bar() -> () 82
  22. 83.

    ; <label>:7: ; preds = %3 %pgocount1 = load i64,

    i64* getelementptr inbounds ([1 x i64], [1 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyFSbyKXKfu_", i64 0, i64 0) %8 = add i64 %pgocount1, 1 store i64 %8, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyFSbyKXKfu_", i64 0, i64 0) br label %9 ; <label>:7: ; preds = %3 %pgocount1 = load i64, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyFSbyKXKfu_", i64 0, i64 0) %8 = add i64 %pgocount1, 1 store i64 %8, i64* getelementptr inbounds ([1 x i64], [1 x i64]* @"__profc_Coverage/ Coverage.swift:$S4Hoge3FooV3baryyFSbyKXKfu_", i64 0, i64 0) br label %9 ͦͷଞͷ෦෼ʹ͍ͭͯ͸ઌ΄Ͳͱಉ͡Ճࢉॲཧ 83
  23. 94.

    ; <label>:2: ; preds = %1 br i1 true, label

    %3, label %._crit_edge ._crit_edge: ; preds = %2 call void @__sanitizer_cov_trace_pc_guard(i32* inttoptr (i64 add (i64 ptrtoint ([5 x i32]* @__sancov_gen_ to i64), i64 4) to i32*)) call void asm sideeffect "", ""() br label %46 ; <label>:3: ; preds = %2 Ұ෦ൈਮ 94
  24. 95.

    ; <label>:2: ; preds = %1 br i1 true, label

    %3, label %._crit_edge ._crit_edge: ; preds = %2 call void @__sanitizer_cov_trace_pc_guard(i32* inttoptr (i64 add (i64 ptrtoint ([5 x i32]* @__sancov_gen_ to i64), i64 4) to i32*)) call void asm sideeffect "", ""() br label %46 ; <label>:3: ; preds = %2 ; <label>:2: ; preds = %1 br i1 true, label %3, label %._crit_edge ._crit_edge: ; preds = %2 call void @__sanitizer_cov_trace_pc_guard(i32* inttoptr (i64 add (i64 ptrtoint ([5 x i32]* @__sancov_gen_ to i64), i64 4) to i32*)) call void asm sideeffect "", ""() br label %46 ; <label>:3: ; preds = %2 ෼ذઌʹcrit_edgeͱ͍͏΋ͷ͕ଘࡏ͢Δ 95
  25. 96.

    ; <label>:2: ; preds = %1 br i1 true, label

    %3, label %._crit_edge ._crit_edge: ; preds = %2 call void @__sanitizer_cov_trace_pc_guard(i32* inttoptr (i64 add (i64 ptrtoint ([5 x i32]* @__sancov_gen_ to i64), i64 4) to i32*)) call void asm sideeffect "", ""() br label %46 ; <label>:3: ; preds = %2 ; <label>:2: ; preds = %1 br i1 true, label %3, label %._crit_edge ._crit_edge: ; preds = %2 call void @__sanitizer_cov_trace_pc_guard(i32* inttoptr (i64 add (i64 ptrtoint ([5 x i32]* @__sancov_gen_ to i64), i64 4) to i32*)) call void asm sideeffect "", ""() br label %46 ; <label>:3: ; preds = %2 ຒΊࠐ·Εͨؔ਺ΛݺΜͰ͍Δ 96
  26. 101.
  27. 103.

    { "covered-points" : ["100000b2d", "100000c22", "100000c9f", "100000ccf", "100000d1c"], "binary-hash" :

    "5CCB31D0F47A427284B9EE58B2C89557D382CD0B", "point-symbol-info" : { "<invalid>" : { "$ss5print_9separator10terminatoryypd_S2StFfA0_" : { "100000c9f" : "0:0" }, "$ss5print_9separator10terminatoryypd_S2StFfA1_" : { "100000ccf" : "0:0" }, "asan.module_dtor" : { "100000d1c" : "0:0" }, "main" : { "100000b2d" : "0:0", "100000c22" : "0:0" } } } } 103
  28. 110.
  29. 118.

    ࢀߟࢿྉ • Code Coverage - Apple Developer
 https://developer.apple.com/library/archive/documentation/ DeveloperTools/Conceptual/testing_with_xcode/chapters/07- code_coverage.html

    • Source-based Code Coverage - Clang 10 documentation
 https://clang.llvm.org/docs/ SourceBasedCodeCoverage.html#exporting-coverage-data • LLVM Code Coverage Mapping Format - LLVM 10 documentation
 https://llvm.org/docs/CoverageMappingFormat.html 118
  30. 119.

    • llvm-cov - emit coverage information - LLVM 10 documentation


    https://llvm.org/docs/CommandGuide/llvm-cov.html • SwiftίϯύΠϥͷΞʔΩςΫνϟ
 https://qiita.com/rintaro/items/3ad640e3938207218c20 • https://github.com/apple/swift • SwiftίϯύΠϥͷManglingͷษڧํ๏
 https://qiita.com/omochimetaru/items/ 60b0d50146e0abbc9b7b 119
  31. 120.

    • LLVM Language Reference Manual - LLVM 10 documentation
 https://llvm.org/docs/LangRef.html

    • AddressSanitizerFlags
 https://github.com/google/sanitizers/wiki/ AddressSanitizerFlags 120
  32. 121.
  33. 127.

    • 3छྨͷग़ྗํ๏ • show / report / export • show

    - ͲͷҐஔ͕௨ա͍ͯ͠ͳ͍͔͕ιʔε ίʔυͱରԠ͚ͮΒΕͯݟΕΔ • report - ֤ϑΝΠϧͷLine / Function / Region coverageͷsummary͕ҰཡͰݟΕΔ • export - JSON΍lcovܗࣜͰग़ྗ͕Ͱ͖Δ 127
  34. 129.

    129

  35. 130.

    • xcrun llvm-cov report -ignore-filename- regex=[pattern] -instr-profile=*.profdata • ਖ਼نදݱͰܭଌ͠ͳ͍ϑΝΠϧΛࢦఆͰ ͖Δ

    • -ignore-filename-regex=.*ViewController.swift
 ͰViewControllerΛআ֎͢ΔͳΜͯ͜ͱ΋ 130