Skip to content

Commit

Permalink
Merge pull request #1122 from m-Peter/skip-coverage-for-scripts-and-t…
Browse files Browse the repository at this point in the history
…ransactions

Add flag for skipping code coverage inspection on scripts and transactions
  • Loading branch information
sideninja authored Jul 25, 2023
2 parents 0bdaa79 + 94d2f81 commit 02c27a2
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 16 deletions.
18 changes: 16 additions & 2 deletions flowkit/tests/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,7 @@ var TestScriptWithFileRead = Resource{
var TestScriptWithCoverage = Resource{
Filename: "testScriptWithCoverage.cdc",
Source: []byte(`
import Test
import "FooContract"
pub let foo = FooContract()
Expand All @@ -429,7 +430,7 @@ var TestScriptWithCoverage = Resource{
let result = foo.getIntegerTrait(input)
// Assert
assert(result == testInputs[input])
Test.assert(result == testInputs[input])
}
}
Expand All @@ -438,7 +439,20 @@ var TestScriptWithCoverage = Resource{
foo.addSpecialNumber(78557, "Sierpinski")
// Assert
assert("Sierpinski" == foo.getIntegerTrait(78557))
Test.assert("Sierpinski" == foo.getIntegerTrait(78557))
}
pub fun testExecuteScript() {
// Arrange
let blockchain = Test.newEmulatorBlockchain()
// Act
let code = "pub fun main(): Int { return 42 }"
let result = blockchain.executeScript(code, [])
let answer = (result.returnValue as! Int?)!
// Assert
Test.assert(answer == 42)
}
`),
}
Expand Down
25 changes: 21 additions & 4 deletions internal/test/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,14 @@ import (
// are considered to be helper/utility scripts for test files.
const helperScriptSubstr = "_helper"

// When the value of flagsTests.CoverCode equals "contracts",
// scripts and transactions are excluded from coverage report.
const contractsCoverCode = "contracts"

type flagsTests struct {
Cover bool `default:"false" flag:"cover" info:"Use the cover flag to calculate coverage report"`
CoverProfile string `default:"coverage.json" flag:"coverprofile" info:"Filename to write the calculated coverage report"`
CoverProfile string `default:"coverage.json" flag:"coverprofile" info:"Filename to write the calculated coverage report. Supported extensions are .json and .lcov"`
CoverCode string `default:"all" flag:"covercode" info:"Use the covercode flag to calculate coverage report only for certain types of code. Available values are \"all\" & \"contracts\""`
}

var testFlags = flagsTests{}
Expand Down Expand Up @@ -86,7 +91,7 @@ func run(
testFiles[filename] = code
}

res, coverageReport, err := testCode(testFiles, state, testFlags.Cover)
res, coverageReport, err := testCode(testFiles, state, testFlags)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -123,12 +128,24 @@ func run(
func testCode(
testFiles map[string][]byte,
state *flowkit.State,
coverageEnabled bool,
flags flagsTests,
) (map[string]cdcTests.Results, *runtime.CoverageReport, error) {
var coverageReport *runtime.CoverageReport
runner := cdcTests.NewTestRunner()
if coverageEnabled {
if flags.Cover {
coverageReport = runtime.NewCoverageReport()
if flags.CoverCode == contractsCoverCode {
coverageReport.WithLocationFilter(
func(location common.Location) bool {
_, addressLoc := location.(common.AddressLocation)
_, stringLoc := location.(common.StringLocation)
// We only allow inspection of AddressLocation or StringLocation,
// since scripts and transactions cannot be attributed to their
// source files anyway.
return addressLoc || stringLoc
},
)
}
runner = runner.WithCoverageReport(coverageReport)
}

Expand Down
126 changes: 116 additions & 10 deletions internal/test/test_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func TestExecutingTests(t *testing.T) {
testFiles := map[string][]byte{
script.Filename: script.Source,
}
results, _, err := testCode(testFiles, state, false)
results, _, err := testCode(testFiles, state, flagsTests{})

require.NoError(t, err)
require.Len(t, results, 1)
Expand All @@ -56,7 +56,7 @@ func TestExecutingTests(t *testing.T) {
testFiles := map[string][]byte{
script.Filename: script.Source,
}
results, _, err := testCode(testFiles, state, false)
results, _, err := testCode(testFiles, state, flagsTests{})

require.NoError(t, err)
require.Len(t, results, 1)
Expand All @@ -81,7 +81,7 @@ func TestExecutingTests(t *testing.T) {
testFiles := map[string][]byte{
script.Filename: script.Source,
}
results, _, err := testCode(testFiles, state, false)
results, _, err := testCode(testFiles, state, flagsTests{})

require.NoError(t, err)
require.Len(t, results, 1)
Expand Down Expand Up @@ -121,7 +121,7 @@ func TestExecutingTests(t *testing.T) {
testFiles := map[string][]byte{
script.Filename: script.Source,
}
results, _, err := testCode(testFiles, state, false)
results, _, err := testCode(testFiles, state, flagsTests{})

require.NoError(t, err)
require.Len(t, results, 1)
Expand All @@ -137,7 +137,7 @@ func TestExecutingTests(t *testing.T) {
testFiles := map[string][]byte{
script.Filename: script.Source,
}
results, _, err := testCode(testFiles, state, false)
results, _, err := testCode(testFiles, state, flagsTests{})

require.NoError(t, err)
require.Len(t, results, 1)
Expand All @@ -161,7 +161,7 @@ func TestExecutingTests(t *testing.T) {
testFiles := map[string][]byte{
script.Filename: script.Source,
}
_, _, err := testCode(testFiles, state, false)
_, _, err := testCode(testFiles, state, flagsTests{})

require.Error(t, err)
assert.Error(
Expand All @@ -186,7 +186,7 @@ func TestExecutingTests(t *testing.T) {
testFiles := map[string][]byte{
script.Filename: script.Source,
}
results, _, err := testCode(testFiles, state, false)
results, _, err := testCode(testFiles, state, flagsTests{})

require.NoError(t, err)
require.Len(t, results, 1)
Expand All @@ -209,11 +209,96 @@ func TestExecutingTests(t *testing.T) {
testFiles := map[string][]byte{
script.Filename: script.Source,
}
results, coverageReport, err := testCode(testFiles, state, true)
flags := flagsTests{
Cover: true,
}
results, coverageReport, err := testCode(testFiles, state, flags)

require.NoError(t, err)
require.Len(t, results, 1)
assert.NoError(t, results[script.Filename][0].Error)
require.Len(t, results[script.Filename], 3)
for _, result := range results[script.Filename] {
assert.NoError(t, result.Error)
}

location := common.StringLocation("FooContract")
coverage := coverageReport.Coverage[location]

assert.Equal(t, []int{}, coverage.MissedLines())
assert.Equal(t, 15, coverage.Statements)
assert.Equal(t, "100.0%", coverage.Percentage())
assert.EqualValues(
t,
map[int]int{
6: 1, 14: 1, 18: 10, 19: 1, 20: 9, 21: 1, 22: 8, 23: 1,
24: 7, 25: 1, 26: 6, 27: 1, 30: 5, 31: 4, 34: 1,
},
coverage.LineHits,
)

assert.True(t, coverageReport.TotalLocations() > 1)
assert.ElementsMatch(
t,
[]string{
"s.7465737400000000000000000000000000000000000000000000000000000000",
"I.Crypto",
"I.Test",
"A.0ae53cb6e3f42a79.FlowToken",
"A.f8d6e0586b0a20c7.FlowStorageFees",
"A.f8d6e0586b0a20c7.FlowDKG",
"A.f8d6e0586b0a20c7.ExampleNFT",
"A.f8d6e0586b0a20c7.NonFungibleToken",
"A.f8d6e0586b0a20c7.FlowIDTableStaking",
"A.f8d6e0586b0a20c7.FlowClusterQC",
"A.f8d6e0586b0a20c7.NodeVersionBeacon",
"A.f8d6e0586b0a20c7.StakingProxy",
"A.f8d6e0586b0a20c7.FUSD",
"A.e5a8b7f23e8b548f.FlowFees",
"A.ee82856bf20e2aa6.FungibleToken",
"A.f8d6e0586b0a20c7.FlowStakingCollection",
"A.f8d6e0586b0a20c7.MetadataViews",
"A.f8d6e0586b0a20c7.ViewResolver",
"A.f8d6e0586b0a20c7.NFTStorefrontV2",
"A.f8d6e0586b0a20c7.NFTStorefront",
"A.f8d6e0586b0a20c7.LockedTokens",
"A.f8d6e0586b0a20c7.FlowServiceAccount",
"A.f8d6e0586b0a20c7.FlowEpoch",
},
coverageReport.ExcludedLocationIDs(),
)
assert.Equal(
t,
"Coverage: 97.2% of statements",
coverageReport.String(),
)
})

t.Run("with code coverage for contracts only", func(t *testing.T) {
t.Parallel()

// Setup
_, state, _ := util.TestMocks(t)

state.Contracts().AddOrUpdate(config.Contract{
Name: tests.ContractFooCoverage.Name,
Location: tests.ContractFooCoverage.Filename,
})

// Execute script
script := tests.TestScriptWithCoverage
testFiles := map[string][]byte{
script.Filename: script.Source,
}
flags := flagsTests{
Cover: true,
CoverCode: contractsCoverCode,
}
results, coverageReport, err := testCode(testFiles, state, flags)

require.NoError(t, err)
require.Len(t, results[script.Filename], 3)
for _, result := range results[script.Filename] {
assert.NoError(t, result.Error)
}

location := common.StringLocation("FooContract")
coverage := coverageReport.Coverage[location]
Expand All @@ -230,12 +315,33 @@ func TestExecutingTests(t *testing.T) {
coverage.LineHits,
)

assert.Equal(t, 1, coverageReport.TotalLocations())
assert.ElementsMatch(
t,
[]string{
"s.7465737400000000000000000000000000000000000000000000000000000000",
"I.Crypto",
"I.Test",
"A.0ae53cb6e3f42a79.FlowToken",
"A.f8d6e0586b0a20c7.FlowStorageFees",
"A.f8d6e0586b0a20c7.FlowDKG",
"A.f8d6e0586b0a20c7.ExampleNFT",
"A.f8d6e0586b0a20c7.NonFungibleToken",
"A.f8d6e0586b0a20c7.FlowIDTableStaking",
"A.f8d6e0586b0a20c7.FlowClusterQC",
"A.f8d6e0586b0a20c7.NodeVersionBeacon",
"A.f8d6e0586b0a20c7.StakingProxy",
"A.f8d6e0586b0a20c7.FUSD",
"A.e5a8b7f23e8b548f.FlowFees",
"A.ee82856bf20e2aa6.FungibleToken",
"A.f8d6e0586b0a20c7.FlowStakingCollection",
"A.f8d6e0586b0a20c7.MetadataViews",
"A.f8d6e0586b0a20c7.ViewResolver",
"A.f8d6e0586b0a20c7.NFTStorefrontV2",
"A.f8d6e0586b0a20c7.NFTStorefront",
"A.f8d6e0586b0a20c7.LockedTokens",
"A.f8d6e0586b0a20c7.FlowServiceAccount",
"A.f8d6e0586b0a20c7.FlowEpoch",
},
coverageReport.ExcludedLocationIDs(),
)
Expand Down

0 comments on commit 02c27a2

Please sign in to comment.