Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up
for free
Xcodeのカバレッジ計測ではなぜブランチカバレッジが取れないのだろうか?
Daiki Katayama
September 06, 2019
Programming
3
2.4k
Xcodeのカバレッジ計測ではなぜブランチカバレッジが取れないのだろうか?
Daiki Katayama
September 06, 2019
Tweet
Share
More Decks by Daiki Katayama
See All by Daiki Katayama
kariad
6
3.6k
kariad
1
1.4k
kariad
2
850
kariad
2
1.9k
kariad
2
560
Other Decks in Programming
See All in Programming
andpad
4
310
coa00
2
190
ybrliiu
0
120
abeta
1
210
joergneumann
0
130
watilde
5
1.5k
taketora
0
120
dqneo
3
340
emmaglorypraise
0
140
madai0517
1
210
deepflow
9
3.6k
takutakahashi
3
310
Featured
See All Featured
jmmastey
10
630
davidbonilla
70
3.6k
marktimemedia
7
400
lynnandtonic
272
16k
jlugia
217
16k
sachag
267
17k
qrush
285
19k
geeforr
332
29k
lara
590
61k
pauljervisheath
195
15k
pedronauck
652
110k
malarkey
119
16k
Transcript
9DPEFͷΧόϨοδܭଌͰ ͳͥϒϥϯνΧόϨοδ͕ औΕͳ͍ͷͩΖ͏͔ʁ J04%$ LBSJBE 1
ࣗݾհ • kariad / @kariad_uu • ยࢁ େथ • ΦΠγοΫεɾϥɾେגࣜձࣾ
• ςετ / ઃܭ / ໊औ͞ͳ 2 ARIAͷ
ΞδΣϯμ • ίʔυΧόϨοδʹ͍ͭͯ • XcodeͰͷίʔυΧόϨοδܭଌͱදࣔ • XcodeͰͷίʔυΧόϨοδܭଌͷΈ • ·ͱΊ 3
ίʔυΧόϨοδʹ͍ͭͯ 4
ίʔυΧόϨοδͱ • ιʔείʔυ͕ͲΕ͚ͩཏ͞Ε͔ͨͷׂ߹ • ԿΛ݅ʹཏΛݟΔ͔ෳͷ؍͕͋ Δ 5
• C0(εςʔτϝϯτΧόϨοδ) ໋ྩจཏɺ໋ྩจ͕ͲΕ͚ͩཏ͞Ε ͔ͨ • C1(ϒϥϯνΧόϨοδ) ذཏɺذ͕ͲΕ͚ͩཏ͞Ε͔ͨ • C2(σΟγδϣϯΧόϨοδ) ݅ཏɺ͕݅ͲΕ͚ͩཏ͞Ε͔ͨ
6
9DPEFͰͷ ίʔυΧόϨοδܭଌ 7
8 ςετΛ࣮ߦͨ͠Β…
ͱͯ؆୯ʂ 9
؆୯ʹऔΕΔ͚Ͳʜ • ͲͷछྨͷΧόϨοδΛऔΔ͔બͰ͖ͳ͍ • ͦͦͲΜͳ݅ͰΧόϨοδऔͬͯΔʁ 10
9DPEFͷ ΧόϨοδܭଌͱදࣔͷ࣮ଶ 11
• ·ͣԿΛ݅ͱͨ͠ΧόϨοδΛදࣔ ͍ͯ͠Δ͔ 12
• ࢀߟʹͳΔͷWWDC 2018ͷ What’s New in Testing https://developer.apple.com/videos/play/ wwdc2018/403/
13
• xccovͷհ෦Ͱ໌֬ʹ Line coverage percentͱݴ͍ͬͯΔ • xccovͷհͰ͋Δ͕ɺҧ͏ͷΛදࣔ ͍ͤͯ͞Δͱߟ͑ͮΒ͍ 14
YDDPWͱ • Apple͕࡞ͬͨΧόϨοδΛਓʹಡΈ͢ ͘දࣔͤ͞Δπʔϧ • JSONͰͷग़ྗͰ͖Δ 15
ΧόϨοδͷݩσʔλ • xccovͰ͏ιʔεBuild/Logs/TestԼͷ 16
YDDPWΛ࣮ͬͯࡍʹ ݟͯΈΔ xcrun xccov view action.xccovreport ΧόϨοδͷ֓ཁΛݟͯΈΔ 17
/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
MVP_ConnpassEventSearch.AppDelegate.applicatio nWillEnterForeground(__C.UIApplication) -> () 0.00% (0/3) ίϝϯτؚΊͯ3ߦ ΧόϨοδXcode্ͷදࣔͱҰக͢Δ 19
9DPEFͰදࣔ͞Ε͍ͯΔ ΧόϨοδߦΛج४ʹܭଌͨ͠ -JOFDPWFSBHF 20
• Line coverageͱ͍͏͜ͱΘ͔ͬͨ • ଞͷΧόϨοδऔΕͳ͍ͷ͔ʁ 21
9DPEFͷ ΧόϨοδܭଌͷΈ͔Β ݟ͍ͯ͘ 22
ͦͦΧόϨοδ Ͳ͏ͬͯऔͬͯΔͷʁ • ώϯτυΩϡϝϯτʹ • https://developer.apple.com/library/archive/ documentation/DeveloperTools/Conceptual/ testing_with_xcode/chapters/07- code_coverage.html 23
$PEFDPWFSBHFJO9DPEFJTB UFTUJOHPQUJPOTVQQPSUFECZ --7. 24
9DPEF --7.ͷ ΧόϨοδܭଌͷΈ 25
--7.ͷΧόϨοδܭଌ • Source-based Code Coverage • SanitizerCoverage • gcov 26
--7.ͷΧόϨοδܭଌ • Source-based Code Coverage • SanitizerCoverage • gcov 27
4PVSDFCBTFE $PEF$PWFSBHF • ASTϓϦϓϩηοαใΛૢ࡞͢Δ͜ ͱ͔ΒSource-basedͱݺΕΔ • ؆୯ʹ݁ՌΛࢹ֮Խ͢Δ͜ͱ·ͰՄೳ • ͓ͦΒ͘࠷ελϯμʔυͳͷ 28
࣮ࡍʹ4XJGUͷ 4PVSDFCBTFE$PEF$PWFSBHF ΛऔͬͯΈΔ 29
1. ΧόϨοδܭଌΛ༗ޮʹͯ͠ίϯύΠϧ 2. ੜ͞ΕͨϓϩάϥϜΛ࣮ߦ 3. ΧόϨοδϨϙʔτͷੜ खॱ 30
main.swift let number = 10 if number % 2 ==
0 { print("ۮ") } ୯७ͳϓϩάϥϜͰܭଌͯ͠ΈΔ 31
ΧόϨοδܭଌΛ ༗ޮʹͯ͠ίϯύΠϧ xcrun swiftc -profile-generate -profile-coverage-mapping main.swift ϓϩάϥϜ 32
ੜ͞Εͨ ϓϩάϥϜΛ࣮ߦ ϓϩάϥϜ EFGBVMUQSPGSBX ΧόϨοδใͷੜσʔλ 33
ΧόϨοδϨϙʔτΛੜ xcrun llvm-profdata merge -o testprof.profdata default.profraw UFTUQSPGQSPGEBUB profrawϑΝΠϧͦͷ··ͩͱϨϙʔτΛग़ྗͰ͖Δ ܗࣜͰͳ͘ΠϯσοΫεΛ͚ͭΔඞཁ͕͋Δ
testprofࣗͰ໋໊ 34
UFTUQSPGQSPGEBUB ࠷ऴతͳΧόϨοδใ͕ೖͬͨϑΝΠϧ ͜ͷঢ়ଶͩͱ·ͩਓ͕ಡΊΔঢ়ଶͰͳ͍ llvm-covΛͬͯΧόϨοδใͷදࣔJSONͰ ͷग़ྗΛߦ͏͜ͱ͕Ͱ͖Δ 35
xcrun llvm-cov show ./main -instr-profile=sample.profdata main.swift ߦʹରԠͨ͠ΧόϨοδใ 36
ccMFUOVNCFS*OU cc ccJGOVNCFS\ ccQSJOU ۮ cc^ 37
• llvm-covҙ֎ͱߴػೳ • htmlͰͷग़ྗϨϙʔτܗࣜͰͷग़ྗʹ ରԠ • ܭଌରʹਖ਼نදݱΛ༻͍ͯಛఆͷϑΝ ΠϧΛؚΊͳ͍͜ͱ • ͍ํ࠷ޙʹ͚ͭ·ͨ͠
38
xcrun llvm-cov export ./main -instr- profile=testprof.profdata main.swift JSONͷΧόϨοδใ ͗ͯ͢εϥΠυʹશͯࡌΓ·ͤΜͰͨ͠ 39
"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
• ࣮Source-based Code Coverage4छྨͷ ΧόϨοδΛܭଌ͢Δ͜ͱ͕Ͱ͖Δ 41
-JOFDPWFSBHF • ߦͰݟͨΧόϨοδ(ίϝϯτؚΉ) • σϑΥϧτͷઃఆ͜Ε • ࣮ࡍʹLineͰ͖߹ΘͤͯΈΔͱશʹҰ க͢ΔͨΊXcodeͰද͍ࣔͯ͠Δͷ͜Ε 42
'VODUJPODPWFSBHF *OTUBOUJBUJPODPWFSBHF • ؔͷݺͼग़͠ճ • ΠϯελϯεԽͷճ 43
3FHJPODPWFSBHF • ίʔυͷྖҬͰଌΔΧόϨοδ • ࡾ߲ԋࢉࢠͳͲ1ߦͰͳ͘ෳͱΈͳ͢ • Source-based Code CoverageͰҰ൪ཻ͕ࡉ ͔͍
44
let result = 10 % 2 == 0 ? true
: false 1ߦ͚ͩͷ؆୯ͳίʔυͷΧόϨοδΛݟͯΈΔ 45
Line coverage Region coverage 46
ɾಉ͡Line coverage͕͋ΔͷͰXcodeͰ Source-based Code CoverageΛར༻ͯͦ͠͏ ɾXcode্දࣔ͞Ε͍ͯΔΧόϨοδ Line coverage͕ͩSource-based Code Coverage
ͱ͍͏͜ͱͳΒܭଌࣗମ4छྨߦΘΕ͍ͯ Δͣ 47
ͱݴ͏͜ͱRegion coverageऔಘͰ͖Δ ͷͰ… 48
BuildϑΥϧμΛআ͘ͱ… 49
• Coverage.profdataϑΝΠϧ͕ଘࡏ͢Δ • *.profdataܗࣜͳͷͰllvm-covΛͬͯݟΔ ͜ͱ͕Ͱ͖Δ 50
xcrun llvm-cov report ../../Products/Debug-iphonesimulator/ {ProductName}.app/{ProductName} -instr-profile=Coverage.profdata 51
• Line coverageΑΓࡉ͔͍Region coverageΛ ؆୯ʹΈΔ͜ͱ͕Ͱ͖Δ • ͔͠͠ຊʹগ͚͔ͩ͠͠ࡉ͔͘ͳ͍͔ ͠Εͳ͍ 52
• && || ͱ͍ͬͨ݅ʹ͍ͭͯ Line coverageͰݕग़Ͱ͖Δ 53
struct Foo { func bar() { let number = 10
if number % 2 == 0 || number == 10 { print("ۮͰ10") } } } 54
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
ϝιου͚ͩͰΈΔͱ100%͕ͩ implicit closureͱͯ͠දࣔ͞Ε͓ͯΓɺ ϑΝΠϧ୯ҐͰཏͰ͖͍ͯͳ͍͜ͱ͕ Θ͔Δ 56
public static func || (lhs: Bool, rhs: @autoclosure () throws
-> Bool) rethrows -> Bool { return lhs ? true : try rhs() } Swiftͷ࣮ͱͯ͠&&||ͷӈลclosureͱͯ͠ ॲཧ͞ΕΔ 57
• closure͕ผͰܭଌ͞Ε͍ͯΔ • ͦͷཧ༝ΛΔͨΊʹSource-based Code Coverage͕ͲͷΑ͏ʹऔಘ͞Ε͍ͯΔ͔ Λ؆୯ʹݟͯΈΔ 58
• Source-based Code CoverageLLVM͕ఏڙ ͢ΔCode Coverage Mapping Formatͱ͍͏ ͷΛར༻ͯ͠ܭଌ͍ͯ͠Δ •
ΦϓγϣϯΛ͚ͭͯίϯύΠϧͨ͠ࡍʹ Ϛοϐϯά༻ͷσʔλ͕ຒΊࠐ·ΕΔ 59
• ͜ͷϚοϐϯάϑΥʔϚοτLLVMΛ όοΫΤϯυͱͯ࣋ͭ͠ϑϩϯτΤϯυ ͷϢχόʔαϧϑΥʔϚοτΛࢦͯ͠ ͍Δ • LLVMΛόοΫΤϯυʹͭશͯͷϑϩϯ τΤϯυͰڞ௨ͯ͠औಘͰ͖ΔΧόϨο δ 60
• LLVMͷυΩϡϝϯτʹCoverage Mapping Formatʹ͍ͭͯઆ໌ͨ͠ͷ͕ଘࡏ͢Δ https://llvm.org/docs/ CoverageMappingFormat.html • ͦΕʹΑΔͱϑϩϯτΤϯυ͕LLVM IRΛ ੜ͢ΔࡍʹຒΊࠐ·ΕΔ
61
• ͪͳΈʹSwiftcͰIRGen.cppͷ performIRGeneration() GenDecl.cppͷ IRGenerator::emitGlobalTopLevel() GenCoverageͷ IRGenModule::emitCoverageMapping() •
llvm/ProfileData/Coverage/CoverageMappingWriter.h 62
ͱ͍͏Θ͚Ͱ--7.*3Λ ݟ͍ͯ͘ 63
xcrun swiftc -emit-ir -profile-generate -profile-coverage-mapping Coverage/main.swift • -emit-irΛΦϓγϣϯͱͯ͢͜͠ͱͰ LLVM IRΛग़ྗ͢Δ͜ͱ͕Ͱ͖Δ
• ΧόϨοδΛ༗ޮʹͯ͠LLVM IRΛग़ྗ 64
ܭଌΦϑ ܭଌΦϯ ͕ࠩͨ͘͞Μ͋Δͷ͕Θ͔Δ 65
@"__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
@"__profc_Coverage/Coverage.swift:$S4Hoge3FooV3baryyF" @"__profc_Coverage/Coverage.swift:__ntd_Foo_line:1:1" @"__profc_Coverage/Coverage.swift: $S4Hoge3FooV3baryyFSbyKXKfu_" ͜ͷ3ͭͷάϩʔόϧมʹ͢Δ ͜ͷ··ͩͱΘ͔Βͳ͍ͷͰσϚϯάϧͯ͠ΈΔ 67
@"__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
• ͜ΕΒͷάϩʔόϧมΧϯλͱ ϚοϐϯάใΛอଘ͍ͯ͠Δͷ 69
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
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
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
ͲΜͳॲཧΛ͍ͯ͠Δ͔ งғؾͰ ݟ͍ͯ͘ 73
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
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
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
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
• ͜ͷॲཧʹΑͬͯͲͷؔͷͲͷϒϩο ΫΛ௨ա͔ͨ͠ͷճΧϯτ͕ߦΘΕ ͍ͯΔ 78
; <label>:3: ; preds = %2 br i1 true, label
%4, label %7 ͨͩͷذ 79
; <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
; <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
; <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
; <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
• ͦͦΧϯτ͢Δࡍʹผͷؔͱ͠ ͯΧϯτ͞Ε͍ͯͨ • ͳͷͰϑΝΠϧ୯ҐͰݟ͔ͭΔ͕ɺϝ ιου୯ҐͰݟ͔ͭΒͳ͔ͬͨ 84
• ͱ͍͏͜ͱ͔ΒLine coverageͰ&&||ͷΧό ϨοδΛݟΔ͜ͱͰ͖Δ • ࠓͷॴࢲ͕ؾ͕͍ͨRegion coverageͰ͔͠ݟͭ ͚ΒΕͳ͍ͷ3߲ԋࢉࢠͱ1ߦʹ·ͱΊͯॻ ͍ͨifจ͘Β͍… •
ͦΕͰLine coverageΑΓࡉ͔͘औΕΔͷͰ Region coverageΛͬͯܭଌ͍͍͔ͯ͠͠Ε ͳ͍ 85
ϒϥϯνΧόϨοδ Ͳ͍ͬͨ͜ • XcodeͰར༻͍ͯ͠ΔΧόϨοδܭଌ͕ Source-based Code CoverageͷͨΊɺXcode্ ͷϏϧυ͔ΒϒϥϯνΧόϨοδΛऔΔ͜ ͱͰ͖ͳ͍ 86
--7.ͷΧόϨοδܭଌ • Source-based Code Coverage • SanitizerCoverage • gcov 87
--7.ͷΧόϨοδܭଌ • Source-based Code Coverage → Θ͔ͬͨ • SanitizerCoverage •
gcov → swiftcʹ࣮͞Ε͍ͯͳͦ͞͏ 88
4BOJUJ[FS$PWFSBHF • LLVMͱswiftcͰऔΕΔ͏ҰͭͷΧόϨοδ • ΤοδͱݺΕΔΧόϨοδΛऔಘͰ͖Δ 89
Τοδͱ if 1 == 1 { print("hogehoge") } 90
A B C ௨ৗ3ͭͷϒϩοΫ 91
A B C D edgeΛ༗ޮʹ͢Δͱ Dͱ͍͏μϛʔϒϩοΫ͕ੜ͞ΕΔ 92
͔ͤͬ͘ͳͷͰ --7.*3ݟΑ͏ 93
; <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
; <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
; <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
• μϛʔϒϩοΫͱLLVM IRͰຊདྷԿͳ ͍ذઌʹൃੜ͢ΔϒϩοΫ 97
ΧόϨοδΛݟͯΈΔ 98
• SanitizerCoverageग़ྗ͕໘ • sancovͱ͍͏toolΛ͏ඞཁ͕͋Δ • LLVMΛผ్DL͠ͳ͍ͱೖ͍ͬͯͳ͍ 99
xcrun swiftc -sanitize=address -sanitize-coverage=edge Coverage/main.swift ASAN_OPTIONS=coverage=1 ./main;wc -c *.sancov main.****.sancov
100
sancov -print-coverage-stats main.52871.sancov ./main all-edges: 5 cov-edges: 5 all-functions: 4
cov-functions: 4 ૯edgeͱΧόʔͨ͠edge͕ݟΕΔ 101
sancov -symbolize main.52871.sancov ./main > main.symcov HTMLͰݟΔͨΊʹγϯϘϥΠζͯ͠ ͋͛Δඞཁ͕͋Δ 102
{ "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
• llvm/tools/sancov/ Լʹ͋Δ coverage-report-server.pyͰ HTTPαʔόΛىಈ͢Δ • coverage-report-server.pybrewͰΠϯε τʔϧͨ͠LLVMʹແ͔ͬͨͷͰผ్DL 104
python3 coverage-report-server.py --symcov ~/workspace/Coverage/ main2.symcov --srcpath ~/workspace/Coverage/ ຊདྷϑΝΠϧ໊͕දࣔ͞ΕΔ͕ͣͩɺinvalidʹͳͬͯ͠· ͍ݟΕͳ͔ͬͨ(sancov͕Linux͔͠αϙʔτ͍ͯ͠ͳ͍ͷͰͦΕ ͕ݪҼ͔͠Εͳ͍)
105
• edgeΧόϨοδΛҰԠݟΕΔ • ͔͠͠edgeΧόϨοδذͷΛج४ ʹݟ͍ͯΔͱ͍͏Θ͚Ͱͳ͍ͷͰϒϥ ϯνΧόϨοδͱগ͠ҟͳΔ 106
ϒϥϯνΧόϨοδ औΕΔͷ͔ 107
औΕ·ͤΜʂʂ 108
• edgeͱϒϥϯνҟͳΔͷͳͷͰݫີ ʹϒϥϯνΧόϨοδΛऔΔΈແ ͔ͬͨ • ͦͦݱঢ়ͷεςʔτϝϯτΧό ϨοδͰແ͔ͬͨ(Line coverage) 109
ँࡑ 110
ϓϩϙʔβϧͷҰ෦ • ҰํͰίʔυΧόϨοδʹ͍͔ͭ͘छྨ͕ ͋ΓɺXcodeͰͦͷҰͭͰ͋Δεςʔτϝ ϯτΧόϨοδ͔͠ܭଌͰ͖ͳ͍ͱ͍͏͜ͱ Λ͝ଘͰ͠ΐ͏͔ɻ 111
ϓϩϙʔβϧͷҰ෦ • ҰํͰίʔυΧόϨοδʹ͍͔ͭ͘छྨ͕ ͋ΓɺXcodeͰͦͷҰͭͰ͋Δεςʔτϝ ϯτΧόϨοδ͔͠ܭଌͰ͖ͳ͍ͱ͍͏͜ͱ Λ͝ଘͰ͠ΐ͏͔ɻ 112 XcodeͰݟΕΔͷ Line coverageͰ͢ʂ
• ͨͩ͠Region coverageͱ͍͏Line coverage ΑΓࡉ͔͍ͷ͕؆୯ʹΈΔ͜ͱ͕Ͱ͖ Δ • %ͰͳΒҰԠedge coverageݟΔ͜ͱ Ͱ͖Δ
113
ͦΜͳίʔυΧόϨοδΛ Ͳ͏ͯ͠ͱΓ͍͔ͨ 114
• ΧόϨοδͲ͕͜ॻ͚͍ͯͳ͍͔Λݟ Δ͜ͱ͕Ͱ͖Δπʔϧ • Ͳ͕͜ॻ͚͍ͯͳ͍͔͔ΕՃ͢Δ ͜ͱͰ͖Δ • (ͨͩ͠ॻ͚͍ͯͳ͍ͱ͜ΖΛશͯॻ͘ ͖͔Ͳ͏͔ผͷ) 115
• ࡉ͔͘νΣοΫͯ͘͠ΕΔ΄Ͳؾ͕͔ ͳ͔ͬͨͱ͜Ζʹؾ͕͚ͭΔ • ͋͘·Ͱิॿπʔϧͱͯ͠͏ 116
·ͱΊ • XcodeͰLine coverage͕දࣔ͞Ε͍ͯΔ • গ͠ࡉ͔͍Region coverageऔΕΔ • ϒϥϯνΧόϨοδऔΕͳ͍͕ɺedgeͰͷˋͳ Β(ҰԠ)ݟΕΔ
• ΧόϨοδΛ্खʹ׆༻ͯ͠ྑ͍ςετϥΠϑΛ 117
ࢀߟࢿྉ • 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
• 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
• LLVM Language Reference Manual - LLVM 10 documentation https://llvm.org/docs/LangRef.html
• AddressSanitizerFlags https://github.com/google/sanitizers/wiki/ AddressSanitizerFlags 120
͓·͚ 121
YDDPWͷ͍ํ 122
xcrun xccov view *.xccovreport ϑΝΠϧຖʹԿˋͱ͍ͬͨΞϓϦέʔ γϣϯશମͷΧόϨοδͷ֓ཁΛݟΔ͜ ͱ͕Ͱ͖Δ 123
xcrun xccov view *.xccovarchive/ --file *.swift ಛఆͷϑΝΠϧͷԿߦ͕Կճ࣮ߦ͞Ε͔ͨ ͷৄࡉΛݟΔ͜ͱ͕Ͱ͖Δ ·ͨϑΝΠϧΛࢦఆ͢Δࡍʹ xcrun
xccov view —file-list *.xccovarchive/ Ͱ֤ϑΝΠϧͷύεΛ֬ೝͰ͖Δ 124
MMWNDPWͷ͍ํ 125
• https://llvm.org/docs/CommandGuide/llvm- cov.html • جຊ͜͜ʹॻ͍ͯ͋Γ·͢ 126
• 3छྨͷग़ྗํ๏ • show / report / export • show
- ͲͷҐஔ͕௨ա͍ͯ͠ͳ͍͔͕ιʔε ίʔυͱରԠ͚ͮΒΕͯݟΕΔ • report - ֤ϑΝΠϧͷLine / Function / Region coverageͷsummary͕ҰཡͰݟΕΔ • export - JSONlcovܗࣜͰग़ྗ͕Ͱ͖Δ 127
• xcrun llvm-cov -show -format html -show- regions -instr-profile=**.profdata ͰHTMLͰιʔείʔυͱରԠͨ͠Region
coverageΛݟΔ͜ͱ͕Ͱ͖Δ 128
129
• xcrun llvm-cov report -ignore-filename- regex=[pattern] -instr-profile=*.profdata • ਖ਼نදݱͰܭଌ͠ͳ͍ϑΝΠϧΛࢦఆͰ ͖Δ
• -ignore-filename-regex=.*ViewController.swift ͰViewControllerΛআ֎͢ΔͳΜͯ͜ͱ 130
͋Γ͕ͱ͏͍͟͝·ͨ͠ 131 Twitter: @kariad_uu