-
Notifications
You must be signed in to change notification settings - Fork 326
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add dependency graph unit tests template, and glClear() example (#2745)
The example demonstrate how to build small captures programmatically and to check it for both expected and unexpected dependencies. The API file changes introduce dependencies between glClear() and glClearColor() / glClearDepthf() / glClearStencil().
- Loading branch information
Showing
6 changed files
with
299 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// Copyright (C) 2019 Google Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package assert | ||
|
||
// OnBoolean is the result of calling ThatBoolean on an Assertion. | ||
// It provides boolean assertion tests. | ||
type OnBoolean struct { | ||
Assertion | ||
value bool | ||
} | ||
|
||
// ThatBoolean returns an OnBoolean for boolean based assertions. | ||
func (a Assertion) ThatBoolean(value bool) OnBoolean { | ||
return OnBoolean{Assertion: a, value: value} | ||
} | ||
|
||
// Equals asserts that the supplied boolean is equal to the expected boolean. | ||
func (o OnBoolean) Equals(expect bool) bool { | ||
return o.Compare(o.value, "==", expect).Test(o.value == expect) | ||
} | ||
|
||
// NotEquals asserts that the supplied boolean is not equal to the test boolean. | ||
func (o OnBoolean) NotEquals(test bool) bool { | ||
return o.Compare(o.value, "!=", test).Test(o.value != test) | ||
} | ||
|
||
// IsTrue asserts that the supplied boolean is true | ||
func (o OnBoolean) IsTrue() bool { | ||
return o.Equals(true) | ||
} | ||
|
||
// IsFalse asserts that the supplied boolean is false | ||
func (o OnBoolean) IsFalse() bool { | ||
return o.Equals(false) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// Copyright (C) 2019 Google Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package assert_test | ||
|
||
import "github.com/google/gapid/core/assert" | ||
|
||
// An example of testing integer values | ||
func ExampleBoolean() { | ||
assert := assert.To(nil) | ||
assert.For("true Equals true").ThatBoolean(true).Equals(true) | ||
assert.For("true NotEquals false").ThatBoolean(true).NotEquals(false) | ||
assert.For("true IsTrue").ThatBoolean(true).IsTrue() | ||
assert.For("false IsFalse").ThatBoolean(false).IsFalse() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
// Copyright (C) 2019 Google Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package gles_test | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/google/gapid/core/assert" | ||
"github.com/google/gapid/core/log" | ||
"github.com/google/gapid/core/memory/arena" | ||
"github.com/google/gapid/core/os/device" | ||
"github.com/google/gapid/core/os/device/bind" | ||
"github.com/google/gapid/gapis/api" | ||
"github.com/google/gapid/gapis/api/gles" | ||
"github.com/google/gapid/gapis/capture" | ||
"github.com/google/gapid/gapis/database" | ||
"github.com/google/gapid/gapis/memory" | ||
"github.com/google/gapid/gapis/resolve/dependencygraph2" | ||
) | ||
|
||
// Test helpers | ||
|
||
// testDependencyCmdName is used as a map key to easily express | ||
// expected dependencies | ||
type testDependencyCmdName struct { | ||
sourceCmdName, targetCmdName string | ||
} | ||
|
||
// getCommandName return the command name of a graph node | ||
func getCommandName(graph dependencygraph2.DependencyGraph, nodeId dependencygraph2.NodeID) string { | ||
node := graph.GetNode(nodeId) | ||
if cmdNode, ok := node.(dependencygraph2.CmdNode); ok { | ||
cmdId := cmdNode.Index[0] | ||
if api.CmdID(cmdId).IsReal() { | ||
command := graph.GetCommand(api.CmdID(cmdId)) | ||
return command.CmdName() | ||
} | ||
} | ||
return "" | ||
} | ||
|
||
// testCaptureAndGraph abstracts the boilerplate for creating a capture | ||
// programmatically, check expected dependencies in its graph, and | ||
// clean out | ||
type testCaptureAndGraph struct { | ||
ctx context.Context | ||
arena arena.Arena | ||
cb gles.CommandBuilder | ||
cmds []api.Cmd | ||
} | ||
|
||
// init runs the boilerplate up to being able to add commands to tc.cmds | ||
func (tc *testCaptureAndGraph) init(t *testing.T) { | ||
tc.ctx = log.Testing(t) | ||
tc.ctx = bind.PutRegistry(tc.ctx, bind.NewRegistry()) | ||
tc.ctx = database.Put(tc.ctx, database.NewInMemory(tc.ctx)) | ||
tc.arena = arena.New() | ||
ctxHandle := memory.BytePtr(1) | ||
displayHandle := memory.BytePtr(2) | ||
surfaceHandle := memory.BytePtr(3) | ||
tc.cb = gles.CommandBuilder{Thread: 0, Arena: tc.arena} | ||
|
||
// Common prologue: make an EGL context | ||
tc.cmds = []api.Cmd{ | ||
tc.cb.EglCreateContext(displayHandle, surfaceHandle, surfaceHandle, memory.Nullptr, ctxHandle), | ||
api.WithExtras( | ||
tc.cb.EglMakeCurrent(displayHandle, surfaceHandle, surfaceHandle, ctxHandle, 0), | ||
gles.NewStaticContextStateForTest(tc.arena), gles.NewDynamicContextStateForTest(tc.arena, 64, 64, false)), | ||
} | ||
} | ||
|
||
// terminate cleans up what need to be | ||
func (tc *testCaptureAndGraph) terminate() { | ||
tc.arena.Dispose() | ||
} | ||
|
||
// checkDependenciesArePresent generate the graph and check if | ||
// expected dependencies present | ||
func (tc *testCaptureAndGraph) checkDependenciesArePresent(t *testing.T, expected, unexpected []testDependencyCmdName) { | ||
// Compute dependency graph | ||
header := &capture.Header{ABI: device.AndroidARM64v8a} | ||
cap, err := capture.NewGraphicsCapture(tc.ctx, tc.arena, t.Name(), header, nil, tc.cmds) | ||
if err != nil { | ||
panic(err) | ||
} | ||
capturePath, err := cap.Path(tc.ctx) | ||
if err != nil { | ||
panic(err) | ||
} | ||
tc.ctx = capture.Put(tc.ctx, capturePath) | ||
|
||
cfg := dependencygraph2.DependencyGraphConfig{ | ||
MergeSubCmdNodes: true, | ||
IncludeInitialCommands: false, | ||
} | ||
graph, err := dependencygraph2.GetDependencyGraph(tc.ctx, capturePath, cfg) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
// Check dependencies | ||
mapExpected := map[testDependencyCmdName]bool{} | ||
for _, dep := range expected { | ||
mapExpected[dep] = false | ||
} | ||
mapUnexpected := map[testDependencyCmdName]bool{} | ||
for _, dep := range unexpected { | ||
mapUnexpected[dep] = false | ||
} | ||
|
||
graph.ForeachDependency( | ||
func(src, tgt dependencygraph2.NodeID) error { | ||
srcCmdName := getCommandName(graph, src) | ||
tgtCmdName := getCommandName(graph, tgt) | ||
dep := testDependencyCmdName{srcCmdName, tgtCmdName} | ||
if _, ok := mapExpected[dep]; ok { | ||
mapExpected[dep] = true | ||
} | ||
if _, ok := mapUnexpected[dep]; ok { | ||
mapUnexpected[dep] = true | ||
} | ||
return nil | ||
}) | ||
|
||
for dep, present := range mapExpected { | ||
assert.For(tc.ctx, fmt.Sprintf("Dependency: %v", dep)).ThatBoolean(present).IsTrue() | ||
} | ||
for dep, present := range mapUnexpected { | ||
assert.For(tc.ctx, fmt.Sprintf("Dependency: %v", dep)).ThatBoolean(present).IsFalse() | ||
} | ||
} | ||
|
||
// Actual tests | ||
|
||
// glClear(GL_COLOR_BUFFER_BIT) depends on glClearColor() | ||
func TestDependencyGlClearColor(t *testing.T) { | ||
var tc testCaptureAndGraph | ||
tc.init(t) | ||
defer tc.terminate() | ||
|
||
tc.cmds = append(tc.cmds, | ||
tc.cb.GlClearColor(1, 1, 1, 1), | ||
tc.cb.GlClearDepthf(1), | ||
tc.cb.GlClearStencil(1), | ||
tc.cb.GlClear(gles.GLbitfield_GL_COLOR_BUFFER_BIT)) | ||
|
||
expected := []testDependencyCmdName{ | ||
testDependencyCmdName{"glClear", "glClearColor"}, | ||
} | ||
|
||
unexpected := []testDependencyCmdName{ | ||
testDependencyCmdName{"glClear", "glClearDepthf"}, | ||
testDependencyCmdName{"glClear", "glClearStencil"}, | ||
} | ||
|
||
tc.checkDependenciesArePresent(t, expected, unexpected) | ||
} | ||
|
||
// glClear(GL_DEPTH_BUFFER_BIT) depends on glClearDepthf() | ||
func TestDependencyGlClearDepthf(t *testing.T) { | ||
var tc testCaptureAndGraph | ||
tc.init(t) | ||
defer tc.terminate() | ||
|
||
tc.cmds = append(tc.cmds, | ||
tc.cb.GlClearColor(1, 1, 1, 1), | ||
tc.cb.GlClearDepthf(1), | ||
tc.cb.GlClearStencil(1), | ||
tc.cb.GlClear(gles.GLbitfield_GL_DEPTH_BUFFER_BIT)) | ||
|
||
expected := []testDependencyCmdName{ | ||
testDependencyCmdName{"glClear", "glClearDepthf"}, | ||
} | ||
|
||
unexpected := []testDependencyCmdName{ | ||
testDependencyCmdName{"glClear", "glClearColor"}, | ||
testDependencyCmdName{"glClear", "glClearStencil"}, | ||
} | ||
|
||
tc.checkDependenciesArePresent(t, expected, unexpected) | ||
} | ||
|
||
// glClear(GL_STENCIL_BUFFER_BIT) depends on glClearStencil() | ||
func TestDependencyGlClearStencil(t *testing.T) { | ||
var tc testCaptureAndGraph | ||
tc.init(t) | ||
defer tc.terminate() | ||
|
||
tc.cmds = append(tc.cmds, | ||
tc.cb.GlClearColor(1, 1, 1, 1), | ||
tc.cb.GlClearDepthf(1), | ||
tc.cb.GlClearStencil(1), | ||
tc.cb.GlClear(gles.GLbitfield_GL_STENCIL_BUFFER_BIT)) | ||
|
||
expected := []testDependencyCmdName{ | ||
testDependencyCmdName{"glClear", "glClearStencil"}, | ||
} | ||
|
||
unexpected := []testDependencyCmdName{ | ||
testDependencyCmdName{"glClear", "glClearColor"}, | ||
testDependencyCmdName{"glClear", "glClearDepthf"}, | ||
} | ||
|
||
tc.checkDependenciesArePresent(t, expected, unexpected) | ||
} |