Revert "delete old things!"
This reverts commit 15b125d401
.
NOTREECHECKS=true
original change breaks android tree
BUG=skia:
Review URL: https://codereview.chromium.org/848073005
This commit is contained in:
parent
15b125d401
commit
8b4489b6e6
1
Makefile
1
Makefile
@ -44,6 +44,7 @@ VALID_TARGETS := \
|
||||
debugger \
|
||||
dm \
|
||||
everything \
|
||||
gm \
|
||||
most \
|
||||
pathops_unittest \
|
||||
pdfviewer \
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,12 @@
|
||||
Baseline images originally generated on a Mac Mini
|
||||
|
||||
Model Name: Mac mini
|
||||
Model Identifier: Macmini4,1
|
||||
Processor Name: Intel Core 2 Duo
|
||||
|
||||
Chipset Model: NVIDIA GeForce 320M
|
||||
|
||||
Ran these commands to generate:
|
||||
GYP_DEFINES="skia_scalar=float" make gm
|
||||
out/Debug/gm -w gm/base-macmini
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,12 @@
|
||||
Baseline images originally generated on a Mac Mini
|
||||
|
||||
Model Name: Mac mini
|
||||
Model Identifier: Macmini4,1
|
||||
Processor Name: Intel Core 2 Duo
|
||||
|
||||
Chipset Model: NVIDIA GeForce 320M
|
||||
|
||||
Ran these commands to generate:
|
||||
GYP_DEFINES="skia_scalar=float" make gm
|
||||
out/Debug/gm -w gm/base-macmini
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,12 @@
|
||||
Baseline images originally generated on a Mac Mini
|
||||
|
||||
Model Name: Mac mini
|
||||
Model Identifier: Macmini4,1
|
||||
Processor Name: Intel Core 2 Duo
|
||||
|
||||
Chipset Model: NVIDIA GeForce 320M
|
||||
|
||||
Ran these commands to generate:
|
||||
GYP_DEFINES="skia_scalar=float" make gm
|
||||
out/Debug/gm -w gm/base-macmini
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,12 @@
|
||||
Baseline images originally generated on a Mac Mini
|
||||
|
||||
Model Name: Mac mini
|
||||
Model Identifier: Macmini4,1
|
||||
Processor Name: Intel Core 2 Duo
|
||||
|
||||
Chipset Model: NVIDIA GeForce 320M
|
||||
|
||||
Ran these commands to generate:
|
||||
GYP_DEFINES="skia_scalar=float" make gm
|
||||
out/Debug/gm -w gm/base-macmini
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,11 @@
|
||||
Baseline images originally generated on our Skia_MacMiniLion_Float builtbot slave.
|
||||
|
||||
Model Name: Mac mini
|
||||
Model Identifier: Macmini4,1
|
||||
Processor Name: Intel Core 2 Duo
|
||||
|
||||
Chipset Model: NVIDIA GeForce 320M
|
||||
|
||||
OS: Mac OS 10.7.2
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,11 @@
|
||||
Baseline images originally generated on our Skia_MacMiniLion_Float builtbot slave.
|
||||
|
||||
Model Name: Mac mini
|
||||
Model Identifier: Macmini4,1
|
||||
Processor Name: Intel Core 2 Duo
|
||||
|
||||
Chipset Model: NVIDIA GeForce 320M
|
||||
|
||||
OS: Mac OS 10.7.2
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,11 @@
|
||||
Baseline images originally generated on our Skia_MacMiniLion_Float builtbot slave.
|
||||
|
||||
Model Name: Mac mini
|
||||
Model Identifier: Macmini4,1
|
||||
Processor Name: Intel Core 2 Duo
|
||||
|
||||
Chipset Model: NVIDIA GeForce 320M
|
||||
|
||||
OS: Mac OS 10.7.2
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,11 @@
|
||||
Baseline images originally generated on our Skia_MacMiniLion_Float builtbot slave.
|
||||
|
||||
Model Name: Mac mini
|
||||
Model Identifier: Macmini4,1
|
||||
Processor Name: Intel Core 2 Duo
|
||||
|
||||
Chipset Model: NVIDIA GeForce 320M
|
||||
|
||||
OS: Mac OS 10.7.2
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1 @@
|
||||
{}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,3 @@
|
||||
{
|
||||
"expected-results": {}
|
||||
}
|
@ -0,0 +1,132 @@
|
||||
{
|
||||
"expected-results": {
|
||||
"imageblurtiled_565.png": {
|
||||
"allowed-digests": [
|
||||
[
|
||||
"bitmap-64bitMD5",
|
||||
1672239788423162481
|
||||
]
|
||||
]
|
||||
},
|
||||
"imageblurtiled_8888.png": {
|
||||
"allowed-digests": [
|
||||
[
|
||||
"bitmap-64bitMD5",
|
||||
6974201924079969276
|
||||
]
|
||||
]
|
||||
},
|
||||
"imageblurtiled_gpu.png": {
|
||||
"allowed-digests": [
|
||||
[
|
||||
"bitmap-64bitMD5",
|
||||
18402970219099615441
|
||||
]
|
||||
]
|
||||
},
|
||||
"imageblurtiled_pdf-poppler.png": {
|
||||
"allowed-digests": [
|
||||
[
|
||||
"bitmap-64bitMD5",
|
||||
7162962487674293114
|
||||
]
|
||||
]
|
||||
},
|
||||
"imagefiltersclipped_565.png": {
|
||||
"allowed-digests": [
|
||||
[
|
||||
"bitmap-64bitMD5",
|
||||
14771974755728278127
|
||||
]
|
||||
]
|
||||
},
|
||||
"imagefiltersclipped_8888.png": {
|
||||
"allowed-digests": [
|
||||
[
|
||||
"bitmap-64bitMD5",
|
||||
14537515405997069608
|
||||
]
|
||||
]
|
||||
},
|
||||
"imagefiltersclipped_gpu.png": {
|
||||
"allowed-digests": [
|
||||
[
|
||||
"bitmap-64bitMD5",
|
||||
11179989646465517468
|
||||
]
|
||||
]
|
||||
},
|
||||
"imagefiltersclipped_pdf-poppler.png": {
|
||||
"allowed-digests": [
|
||||
[
|
||||
"bitmap-64bitMD5",
|
||||
3854266854123865664
|
||||
]
|
||||
]
|
||||
},
|
||||
"imagefiltersscaled_565.png": {
|
||||
"allowed-digests": [
|
||||
[
|
||||
"bitmap-64bitMD5",
|
||||
15769177648683788265
|
||||
]
|
||||
]
|
||||
},
|
||||
"imagefiltersscaled_8888.png": {
|
||||
"allowed-digests": [
|
||||
[
|
||||
"bitmap-64bitMD5",
|
||||
18437708945397499005
|
||||
]
|
||||
]
|
||||
},
|
||||
"imagefiltersscaled_gpu.png": {
|
||||
"allowed-digests": [
|
||||
[
|
||||
"bitmap-64bitMD5",
|
||||
8877499313441323086
|
||||
]
|
||||
]
|
||||
},
|
||||
"imagefiltersscaled_pdf-poppler.png": {
|
||||
"allowed-digests": [
|
||||
[
|
||||
"bitmap-64bitMD5",
|
||||
7403124810876127284
|
||||
]
|
||||
]
|
||||
},
|
||||
"resizeimagefilter_565.png": {
|
||||
"allowed-digests": [
|
||||
[
|
||||
"bitmap-64bitMD5",
|
||||
11574452324482789141
|
||||
]
|
||||
]
|
||||
},
|
||||
"resizeimagefilter_8888.png": {
|
||||
"allowed-digests": [
|
||||
[
|
||||
"bitmap-64bitMD5",
|
||||
15004076002839832883
|
||||
]
|
||||
]
|
||||
},
|
||||
"resizeimagefilter_gpu.png": {
|
||||
"allowed-digests": [
|
||||
[
|
||||
"bitmap-64bitMD5",
|
||||
3830823404733713302
|
||||
]
|
||||
]
|
||||
},
|
||||
"resizeimagefilter_pdf-poppler.png": {
|
||||
"allowed-digests": [
|
||||
[
|
||||
"bitmap-64bitMD5",
|
||||
7720572764086610133
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,7 @@
|
||||
Baseline images generated on:
|
||||
|
||||
Shuttle PC with Intel Core i7-2600
|
||||
with Windows 7 installed
|
||||
and using the CPU's built-in GPU (so-called "Intel HD Graphics 3000")
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,7 @@
|
||||
Baseline images generated on:
|
||||
|
||||
Shuttle PC with Intel Core i7-2600
|
||||
with Windows 7 installed
|
||||
and using the CPU's built-in GPU (so-called "Intel HD Graphics 3000")
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,7 @@
|
||||
Baseline images generated on:
|
||||
|
||||
Shuttle PC with Intel Core i7-2600
|
||||
with Windows 7 installed
|
||||
and using the CPU's built-in GPU (so-called "Intel HD Graphics 3000")
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,7 @@
|
||||
Baseline images generated on:
|
||||
|
||||
Shuttle PC with Intel Core i7-2600
|
||||
with Windows 7 installed
|
||||
and using the CPU's built-in GPU (so-called "Intel HD Graphics 3000")
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,7 @@
|
||||
Baseline images generated on:
|
||||
|
||||
Shuttle PC with Intel Core i7-2600
|
||||
with Windows 7 installed
|
||||
and using the CPU's built-in GPU (so-called "Intel HD Graphics 3000")
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,7 @@
|
||||
Baseline images generated on:
|
||||
|
||||
Shuttle PC with Intel Core i7-2600
|
||||
with Windows 7 installed
|
||||
and using the CPU's built-in GPU (so-called "Intel HD Graphics 3000")
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,7 @@
|
||||
Baseline images generated on:
|
||||
|
||||
Shuttle PC with Intel Core i7-2600
|
||||
with Windows 7 installed
|
||||
and using the CPU's built-in GPU (so-called "Intel HD Graphics 3000")
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,7 @@
|
||||
Baseline images generated on:
|
||||
|
||||
Shuttle PC with Intel Core i7-2600
|
||||
with Windows 7 installed
|
||||
and using the CPU's built-in GPU (so-called "Intel HD Graphics 3000")
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
86
expectations/gm/ignored-tests.txt
Normal file
86
expectations/gm/ignored-tests.txt
Normal file
@ -0,0 +1,86 @@
|
||||
# Failures of any GM tests listed in this file will be ignored [1], as
|
||||
# if they had been marked "ignore-failure": true in the per-builder
|
||||
# expected-results.json files.
|
||||
#
|
||||
# The idea is that, if you modify a GM test in such a way that you know it will
|
||||
# require rebaselines on multiple platforms, you should add that test's name to
|
||||
# this list within the same CL that modifies the test.
|
||||
# Then, AS SOON AS POSSIBLE, you should rebaseline the tests (they will show up
|
||||
# as status "failure-ignored") and remove the line you added to this file.
|
||||
# If there are any lingering failures that need to be suppressed (ignored), you
|
||||
# MUST move those suppressions into the per-builder expected-results.json files.
|
||||
#
|
||||
# The test name must match exactly (no partial string matches).
|
||||
# See http://skbug.com/2022
|
||||
#
|
||||
# Any lines starting with '#' are comments and will be ignored.
|
||||
# Other than that, each line must either be whitespace or list just one test.
|
||||
#
|
||||
# For more information, see https://code.google.com/p/skia/issues/detail?id=1600
|
||||
# ('GM expectations: create tool to suppress failures until new baselines are
|
||||
# checked in')
|
||||
#
|
||||
#
|
||||
# [1] Differences between renderModes (e.g., normal rendering path and
|
||||
# "serialized") are NEVER ignored. See
|
||||
# https://code.google.com/p/skia/issues/detail?id=1748 ('gm: add new result
|
||||
# type, RenderModeMismatch')
|
||||
|
||||
# EXAMPLES: (remove the first '#' on each line)
|
||||
#
|
||||
## Added as part of MADE-UP BUG
|
||||
## http://skbug.com/123456 : ignoring failures on gradtext GM test
|
||||
## epoger will rebaseline by 25 Dec 2013
|
||||
#gradtext
|
||||
|
||||
# egdaniel
|
||||
colortype_xfermodes
|
||||
mixed_xfermodes
|
||||
|
||||
# reed - rebase after mipmap level improvement
|
||||
coloremoji
|
||||
downsamplebitmap_image_medium_mandrill_512
|
||||
downsamplebitmap_image_medium_mandrill_132x132_12x12
|
||||
downsamplebitmap_image_medium_mandrill_512.png
|
||||
downsamplebitmap_image_medium_mandrill_132x132_12x12.astc
|
||||
downsamplebitmap_checkerboard_medium_512_256
|
||||
downsamplebitmap_text_medium_72.00pt
|
||||
filterbitmap_checkerboard_4_4
|
||||
filterbitmap_checkerboard_32_2
|
||||
filterbitmap_checkerboard_32_8
|
||||
filterbitmap_checkerboard_32_32
|
||||
filterbitmap_checkerboard_192_192
|
||||
filterbitmap_image_color_wheel.png
|
||||
filterbitmap_image_mandrill_16.png
|
||||
filterbitmap_image_mandrill_32.png
|
||||
filterbitmap_image_mandrill_64.png
|
||||
filterbitmap_image_mandrill_128.png
|
||||
filterbitmap_image_mandrill_256.png
|
||||
filterbitmap_image_mandrill_512.png
|
||||
filterbitmap_text_3.00pt
|
||||
filterbitmap_text_7.00pt
|
||||
filterbitmap_text_10.00pt
|
||||
filterindiabox
|
||||
fontmgr_iter
|
||||
downsamplebitmap_image_high_mandrill_132x132_12x12.astc
|
||||
downsamplebitmap_image_high_mandrill_512.png
|
||||
downsamplebitmap_text_high_72.00pt_8888.png
|
||||
|
||||
# robertphillips - skia:2995
|
||||
blurrects
|
||||
|
||||
# reed - rebase after HQ filter change
|
||||
bleed
|
||||
|
||||
# sugoi https://codereview.chromium.org/646213004/
|
||||
# New shadow only option in SkDropShadowImageFilter
|
||||
dropshadowimagefilter
|
||||
|
||||
# fmalita - rebaseline for http://crbug.com/447707
|
||||
pictureshader
|
||||
|
||||
# bsalomon slight change to image-surface GM on gpu
|
||||
image-surface
|
||||
|
||||
|
||||
|
52
expectations/gm/loader.js
Normal file
52
expectations/gm/loader.js
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* GMExpectedResultsLoader:
|
||||
* Reads an expected-results.json file, and imports its data into $scope.
|
||||
*/
|
||||
var GMExpectedResultsLoader = angular.module(
|
||||
'GMExpectedResultsLoader',
|
||||
[],
|
||||
function($httpProvider) {
|
||||
/* Override transformResponse so that the numeric checksums are interpreted as
|
||||
* strings instead, since Javascript cannot handle 64-bit integers. */
|
||||
$httpProvider.defaults.transformResponse = function(data, headersGetter) {
|
||||
return JSON.parse(data.replace(/\s(\d+)\s/g, " \"$1\" "));
|
||||
}
|
||||
}
|
||||
);
|
||||
GMExpectedResultsLoader.controller(
|
||||
'GMExpectedResultsLoader.Controller',
|
||||
function($scope, $http) {
|
||||
/* When the changePlatformPath function is called, download expected-results.json
|
||||
* from the desired platform directory.
|
||||
*
|
||||
* When the JSON is received, predigest it and return it to the frontend as
|
||||
* $scope.gmExpectedResults .
|
||||
*/
|
||||
$scope.changePlatformPath = function() {
|
||||
$http.get($scope.platformPath + "/expected-results.json").success(
|
||||
function(response) {
|
||||
var jsonResults = [];
|
||||
var imageNameRegex = /^(.+)_([^_]+).png/;
|
||||
angular.forEach(response['expected-results'], function(imageExpectations, imageName) {
|
||||
var matched = imageNameRegex.exec(imageName);
|
||||
var allowedImages = [];
|
||||
angular.forEach(imageExpectations['allowed-digests'], function(allowedDigest, key) {
|
||||
var thisImage = {
|
||||
hashType: allowedDigest[0], hashValue: allowedDigest[1]
|
||||
};
|
||||
allowedImages.push(thisImage);
|
||||
});
|
||||
var thisResult = {
|
||||
test: matched[1], config: matched[2],
|
||||
allowedImages: allowedImages,
|
||||
bugs: imageExpectations['bugs'],
|
||||
reviewedByHuman: imageExpectations['reviewed-by-human']
|
||||
};
|
||||
jsonResults.push(thisResult);
|
||||
});
|
||||
$scope.gmExpectedResults = jsonResults;
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
);
|
153
expectations/gm/view-platform.html
Normal file
153
expectations/gm/view-platform.html
Normal file
@ -0,0 +1,153 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html ng-app="GMExpectedResultsLoader">
|
||||
|
||||
<head>
|
||||
<title>View GM Expected Results for One Platform</title>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.min.js"></script>
|
||||
<script src="loader.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div ng-controller="GMExpectedResultsLoader.Controller" >
|
||||
|
||||
Pick a platform...
|
||||
<select ng-model="platformPath" ng-change="changePlatformPath()">
|
||||
|
||||
<!-- Generated the option lines as follows:
|
||||
$ cd expectations/gm
|
||||
$ ALL=$(ls -d Test*)
|
||||
$ for ONE in $ALL; do echo " <option value=\"$ONE\">$ONE</option>"; done
|
||||
|
||||
TODO(epoger): Once https://code.google.com/p/skia/issues/detail?id=1544
|
||||
('live query of builder list makes rebaseline.py slow to start up') has been
|
||||
resolved, we should use similar techniques to populate this list automatically.
|
||||
-->
|
||||
|
||||
<option value="Test-Android-GalaxyNexus-SGX540-Arm7-Debug">Test-Android-GalaxyNexus-SGX540-Arm7-Debug</option>
|
||||
<option value="Test-Android-GalaxyNexus-SGX540-Arm7-Debug-Trybot">Test-Android-GalaxyNexus-SGX540-Arm7-Debug-Trybot</option>
|
||||
<option value="Test-Android-GalaxyNexus-SGX540-Arm7-Release">Test-Android-GalaxyNexus-SGX540-Arm7-Release</option>
|
||||
<option value="Test-Android-GalaxyNexus-SGX540-Arm7-Release-Trybot">Test-Android-GalaxyNexus-SGX540-Arm7-Release-Trybot</option>
|
||||
<option value="Test-Android-IntelRhb-SGX544-x86-Debug">Test-Android-IntelRhb-SGX544-x86-Debug</option>
|
||||
<option value="Test-Android-IntelRhb-SGX544-x86-Debug-Trybot">Test-Android-IntelRhb-SGX544-x86-Debug-Trybot</option>
|
||||
<option value="Test-Android-IntelRhb-SGX544-x86-Release">Test-Android-IntelRhb-SGX544-x86-Release</option>
|
||||
<option value="Test-Android-Nexus10-MaliT604-Arm7-Debug">Test-Android-Nexus10-MaliT604-Arm7-Debug</option>
|
||||
<option value="Test-Android-Nexus10-MaliT604-Arm7-Release">Test-Android-Nexus10-MaliT604-Arm7-Release</option>
|
||||
<option value="Test-Android-Nexus4-Adreno320-Arm7-Debug">Test-Android-Nexus4-Adreno320-Arm7-Debug</option>
|
||||
<option value="Test-Android-Nexus4-Adreno320-Arm7-Debug-Trybot">Test-Android-Nexus4-Adreno320-Arm7-Debug-Trybot</option>
|
||||
<option value="Test-Android-Nexus4-Adreno320-Arm7-Release">Test-Android-Nexus4-Adreno320-Arm7-Release</option>
|
||||
<option value="Test-Android-Nexus4-Adreno320-Arm7-Release-Trybot">Test-Android-Nexus4-Adreno320-Arm7-Release-Trybot</option>
|
||||
<option value="Test-Android-Nexus7-Tegra3-Arm7-Debug">Test-Android-Nexus7-Tegra3-Arm7-Debug</option>
|
||||
<option value="Test-Android-Nexus7-Tegra3-Arm7-Debug-Trybot">Test-Android-Nexus7-Tegra3-Arm7-Debug-Trybot</option>
|
||||
<option value="Test-Android-Nexus7-Tegra3-Arm7-Release">Test-Android-Nexus7-Tegra3-Arm7-Release</option>
|
||||
<option value="Test-Android-NexusS-SGX540-Arm7-Debug">Test-Android-NexusS-SGX540-Arm7-Debug</option>
|
||||
<option value="Test-Android-NexusS-SGX540-Arm7-Debug-Trybot">Test-Android-NexusS-SGX540-Arm7-Debug-Trybot</option>
|
||||
<option value="Test-Android-NexusS-SGX540-Arm7-Release">Test-Android-NexusS-SGX540-Arm7-Release</option>
|
||||
<option value="Test-Android-RazrI-SGX540-x86-Debug">Test-Android-RazrI-SGX540-x86-Debug</option>
|
||||
<option value="Test-Android-RazrI-SGX540-x86-Release">Test-Android-RazrI-SGX540-x86-Release</option>
|
||||
<option value="Test-Android-Xoom-Tegra2-Arm7-Debug">Test-Android-Xoom-Tegra2-Arm7-Debug</option>
|
||||
<option value="Test-Android-Xoom-Tegra2-Arm7-Release">Test-Android-Xoom-Tegra2-Arm7-Release</option>
|
||||
<option value="Test-ChromeOS-Alex-GMA3150-x86-Debug">Test-ChromeOS-Alex-GMA3150-x86-Debug</option>
|
||||
<option value="Test-ChromeOS-Alex-GMA3150-x86-Debug-Trybot">Test-ChromeOS-Alex-GMA3150-x86-Debug-Trybot</option>
|
||||
<option value="Test-ChromeOS-Alex-GMA3150-x86-Release">Test-ChromeOS-Alex-GMA3150-x86-Release</option>
|
||||
<option value="Test-ChromeOS-Alex-GMA3150-x86-Release-Trybot">Test-ChromeOS-Alex-GMA3150-x86-Release-Trybot</option>
|
||||
<option value="Test-ChromeOS-Daisy-MaliT604-Arm7-Debug">Test-ChromeOS-Daisy-MaliT604-Arm7-Debug</option>
|
||||
<option value="Test-ChromeOS-Daisy-MaliT604-Arm7-Debug-Trybot">Test-ChromeOS-Daisy-MaliT604-Arm7-Debug-Trybot</option>
|
||||
<option value="Test-ChromeOS-Daisy-MaliT604-Arm7-Release">Test-ChromeOS-Daisy-MaliT604-Arm7-Release</option>
|
||||
<option value="Test-ChromeOS-Daisy-MaliT604-Arm7-Release-Trybot">Test-ChromeOS-Daisy-MaliT604-Arm7-Release-Trybot</option>
|
||||
<option value="Test-ChromeOS-Link-HD4000-x86_64-Debug">Test-ChromeOS-Link-HD4000-x86_64-Debug</option>
|
||||
<option value="Test-ChromeOS-Link-HD4000-x86_64-Debug-Trybot">Test-ChromeOS-Link-HD4000-x86_64-Debug-Trybot</option>
|
||||
<option value="Test-ChromeOS-Link-HD4000-x86_64-Release">Test-ChromeOS-Link-HD4000-x86_64-Release</option>
|
||||
<option value="Test-ChromeOS-Link-HD4000-x86_64-Release-Trybot">Test-ChromeOS-Link-HD4000-x86_64-Release-Trybot</option>
|
||||
<option value="Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Debug">Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Debug</option>
|
||||
<option value="Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Debug-Trybot">Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Debug-Trybot</option>
|
||||
<option value="Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Release">Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Release</option>
|
||||
<option value="Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Release-Trybot">Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Release-Trybot</option>
|
||||
<option value="Test-Mac10.6-MacMini4.1-GeForce320M-x86-Debug">Test-Mac10.6-MacMini4.1-GeForce320M-x86-Debug</option>
|
||||
<option value="Test-Mac10.6-MacMini4.1-GeForce320M-x86-Debug-Trybot">Test-Mac10.6-MacMini4.1-GeForce320M-x86-Debug-Trybot</option>
|
||||
<option value="Test-Mac10.6-MacMini4.1-GeForce320M-x86-Release">Test-Mac10.6-MacMini4.1-GeForce320M-x86-Release</option>
|
||||
<option value="Test-Mac10.6-MacMini4.1-GeForce320M-x86-Release-Trybot">Test-Mac10.6-MacMini4.1-GeForce320M-x86-Release-Trybot</option>
|
||||
<option value="Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug">Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug</option>
|
||||
<option value="Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug-Trybot">Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug-Trybot</option>
|
||||
<option value="Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Release">Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Release</option>
|
||||
<option value="Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Release-Trybot">Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Release-Trybot</option>
|
||||
<option value="Test-Mac10.7-MacMini4.1-GeForce320M-x86-Debug">Test-Mac10.7-MacMini4.1-GeForce320M-x86-Debug</option>
|
||||
<option value="Test-Mac10.7-MacMini4.1-GeForce320M-x86-Debug-Trybot">Test-Mac10.7-MacMini4.1-GeForce320M-x86-Debug-Trybot</option>
|
||||
<option value="Test-Mac10.7-MacMini4.1-GeForce320M-x86-Release">Test-Mac10.7-MacMini4.1-GeForce320M-x86-Release</option>
|
||||
<option value="Test-Mac10.7-MacMini4.1-GeForce320M-x86-Release-Trybot">Test-Mac10.7-MacMini4.1-GeForce320M-x86-Release-Trybot</option>
|
||||
<option value="Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug">Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug</option>
|
||||
<option value="Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug-Trybot">Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug-Trybot</option>
|
||||
<option value="Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Release">Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Release</option>
|
||||
<option value="Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Release-Trybot">Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Release-Trybot</option>
|
||||
<option value="Test-Mac10.8-MacMini4.1-GeForce320M-x86-Debug">Test-Mac10.8-MacMini4.1-GeForce320M-x86-Debug</option>
|
||||
<option value="Test-Mac10.8-MacMini4.1-GeForce320M-x86-Debug-Trybot">Test-Mac10.8-MacMini4.1-GeForce320M-x86-Debug-Trybot</option>
|
||||
<option value="Test-Mac10.8-MacMini4.1-GeForce320M-x86-Release">Test-Mac10.8-MacMini4.1-GeForce320M-x86-Release</option>
|
||||
<option value="Test-Mac10.8-MacMini4.1-GeForce320M-x86-Release-Trybot">Test-Mac10.8-MacMini4.1-GeForce320M-x86-Release-Trybot</option>
|
||||
<option value="Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Debug">Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Debug</option>
|
||||
<option value="Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Debug-Trybot">Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Debug-Trybot</option>
|
||||
<option value="Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release">Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release</option>
|
||||
<option value="Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release-Trybot">Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release-Trybot</option>
|
||||
<option value="Test-Ubuntu12-ShuttleA-ATI5770-x86-Debug">Test-Ubuntu12-ShuttleA-ATI5770-x86-Debug</option>
|
||||
<option value="Test-Ubuntu12-ShuttleA-ATI5770-x86-Debug-Trybot">Test-Ubuntu12-ShuttleA-ATI5770-x86-Debug-Trybot</option>
|
||||
<option value="Test-Ubuntu12-ShuttleA-ATI5770-x86-Release">Test-Ubuntu12-ShuttleA-ATI5770-x86-Release</option>
|
||||
<option value="Test-Ubuntu12-ShuttleA-ATI5770-x86-Release-Trybot">Test-Ubuntu12-ShuttleA-ATI5770-x86-Release-Trybot</option>
|
||||
<option value="Test-Ubuntu12-ShuttleA-HD2000-x86_64-Release-Valgrind">Test-Ubuntu12-ShuttleA-HD2000-x86_64-Release-Valgrind</option>
|
||||
<option value="Test-Ubuntu12-ShuttleA-HD2000-x86_64-Release-Valgrind-Trybot">Test-Ubuntu12-ShuttleA-HD2000-x86_64-Release-Valgrind-Trybot</option>
|
||||
<option value="Test-Ubuntu12-ShuttleA-NoGPU-x86_64-Debug">Test-Ubuntu12-ShuttleA-NoGPU-x86_64-Debug</option>
|
||||
<option value="Test-Ubuntu12-ShuttleA-NoGPU-x86_64-Debug-Trybot">Test-Ubuntu12-ShuttleA-NoGPU-x86_64-Debug-Trybot</option>
|
||||
<option value="Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN">Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN</option>
|
||||
<option value="Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN-Trybot">Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN-Trybot</option>
|
||||
<option value="Test-Win7-ShuttleA-HD2000-x86_64-Debug">Test-Win7-ShuttleA-HD2000-x86_64-Debug</option>
|
||||
<option value="Test-Win7-ShuttleA-HD2000-x86_64-Debug-Trybot">Test-Win7-ShuttleA-HD2000-x86_64-Debug-Trybot</option>
|
||||
<option value="Test-Win7-ShuttleA-HD2000-x86_64-Release">Test-Win7-ShuttleA-HD2000-x86_64-Release</option>
|
||||
<option value="Test-Win7-ShuttleA-HD2000-x86_64-Release-Trybot">Test-Win7-ShuttleA-HD2000-x86_64-Release-Trybot</option>
|
||||
<option value="Test-Win7-ShuttleA-HD2000-x86-Debug">Test-Win7-ShuttleA-HD2000-x86-Debug</option>
|
||||
<option value="Test-Win7-ShuttleA-HD2000-x86-Debug-ANGLE">Test-Win7-ShuttleA-HD2000-x86-Debug-ANGLE</option>
|
||||
<option value="Test-Win7-ShuttleA-HD2000-x86-Debug-ANGLE-Trybot">Test-Win7-ShuttleA-HD2000-x86-Debug-ANGLE-Trybot</option>
|
||||
<option value="Test-Win7-ShuttleA-HD2000-x86-Debug-DirectWrite">Test-Win7-ShuttleA-HD2000-x86-Debug-DirectWrite</option>
|
||||
<option value="Test-Win7-ShuttleA-HD2000-x86-Debug-DirectWrite-Trybot">Test-Win7-ShuttleA-HD2000-x86-Debug-DirectWrite-Trybot</option>
|
||||
<option value="Test-Win7-ShuttleA-HD2000-x86-Debug-Trybot">Test-Win7-ShuttleA-HD2000-x86-Debug-Trybot</option>
|
||||
<option value="Test-Win7-ShuttleA-HD2000-x86-Release">Test-Win7-ShuttleA-HD2000-x86-Release</option>
|
||||
<option value="Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE">Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE</option>
|
||||
<option value="Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE-Trybot">Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE-Trybot</option>
|
||||
<option value="Test-Win7-ShuttleA-HD2000-x86-Release-DirectWrite">Test-Win7-ShuttleA-HD2000-x86-Release-DirectWrite</option>
|
||||
<option value="Test-Win7-ShuttleA-HD2000-x86-Release-DirectWrite-Trybot">Test-Win7-ShuttleA-HD2000-x86-Release-DirectWrite-Trybot</option>
|
||||
<option value="Test-Win7-ShuttleA-HD2000-x86-Release-Trybot">Test-Win7-ShuttleA-HD2000-x86-Release-Trybot</option>
|
||||
|
||||
</select>
|
||||
|
||||
<p>
|
||||
Expected GM results for platform {{platformPath}}:
|
||||
|
||||
<table border="1">
|
||||
<tr>
|
||||
<th>Test/Config</th>
|
||||
<th>Allowed Images</th>
|
||||
<th>Bugs</th>
|
||||
<th>Reviewed By Human?</th>
|
||||
</tr>
|
||||
<tr ng-repeat="result in gmExpectedResults">
|
||||
<td>{{result.test}}_{{result.config}}</td>
|
||||
<td><span ng-repeat="image in result.allowedImages">
|
||||
<a target="_blank"
|
||||
href="http://chromium-skia-gm.commondatastorage.googleapis.com/gm/{{image.hashType}}/{{result.test}}/{{image.hashValue}}.png">
|
||||
{{image.hashValue}}</a><br>
|
||||
</span></td>
|
||||
<td><span ng-repeat="bug in result.bugs">
|
||||
<a href="https://code.google.com/p/skia/issues/detail?id={{bug}}">{{bug}} </a>
|
||||
</span></td>
|
||||
<td>{{result.reviewedByHuman}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- TODO(epoger): Can we get the base URLs (commondatastorage and
|
||||
issues list) from
|
||||
https://skia.googlesource.com/buildbot/+/3de60f3003e3/site_config/global_variables.json ?
|
||||
I tried importing the
|
||||
http://skia.googlecode.com/svn/buildbot/skia_tools.js script and using
|
||||
that to do so, but I got Access-Control-Allow-Origin errors.
|
||||
-->
|
||||
|
||||
</body>
|
||||
</html>
|
3
expectations/gm/whitespace.txt
Normal file
3
expectations/gm/whitespace.txt
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
|
||||
|
1
gm/__init__.py
Normal file
1
gm/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
# Allow Python import of this directory.
|
104
gm/copy_config.py
Executable file
104
gm/copy_config.py
Executable file
@ -0,0 +1,104 @@
|
||||
#!/usr/bin/python
|
||||
# Copyright (c) 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Utility to duplicate a config in some subset of our GM expectation files.
|
||||
|
||||
Created for http://skbug.com/2752 ('split existing "gpu" GM results into "gl"
|
||||
and "gles"')
|
||||
|
||||
Run with -h to see usage.
|
||||
|
||||
Example command lines:
|
||||
copy_config.py gl gles '.*Mac10.7.*'
|
||||
|
||||
TODO(epoger): Once https://codereview.chromium.org/397103003/ is committed,
|
||||
we should add a unittest. Until then, we can test this as follows:
|
||||
|
||||
OLD=expectations/gm && NEW=/tmp/expectations && \
|
||||
rm -rf $NEW && \
|
||||
cp -a $OLD $NEW && \
|
||||
gm/copy_config.py 8888 8888-copy '.*Mac10.7.*' \
|
||||
--expectations-root $NEW && \
|
||||
diff --recursive $OLD $NEW
|
||||
"""
|
||||
__author__ = 'Elliot Poger'
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
|
||||
import gm_json
|
||||
|
||||
DEFAULT_EXPECTATIONS_ROOT = os.path.join(
|
||||
os.path.dirname(__file__), os.pardir, 'expectations', 'gm')
|
||||
IMAGE_FILENAME_RE = re.compile(gm_json.IMAGE_FILENAME_PATTERN)
|
||||
|
||||
|
||||
class Copier(object):
|
||||
|
||||
def __init__(self, args):
|
||||
"""
|
||||
Params:
|
||||
args: the Namespace object generated by argparse.parse_args()
|
||||
"""
|
||||
self._args = args
|
||||
|
||||
def run(self):
|
||||
"""Perform all the duplications."""
|
||||
for path in self._get_file_list():
|
||||
self._duplicate_config(path=path,
|
||||
old=self._args.old_config_name,
|
||||
new=self._args.new_config_name)
|
||||
|
||||
def _duplicate_config(self, path, old, new):
|
||||
"""Duplicates all instances of a config within a GM expectations file.
|
||||
|
||||
Params:
|
||||
path: path to file which will be modified in place
|
||||
old: old config name
|
||||
new: new config name
|
||||
"""
|
||||
dic = gm_json.LoadFromFile(file_path=path)
|
||||
expected_results = dic[gm_json.JSONKEY_EXPECTEDRESULTS]
|
||||
orig_keys = expected_results.keys()
|
||||
for key in orig_keys:
|
||||
result = expected_results[key]
|
||||
(testname, config) = IMAGE_FILENAME_RE.match(key).groups()
|
||||
if config == old:
|
||||
config = new
|
||||
key = '%s_%s.png' % (testname, config)
|
||||
expected_results[key] = result
|
||||
gm_json.WriteToFile(json_dict=dic, file_path=path)
|
||||
|
||||
def _get_file_list(self):
|
||||
"""Returns the list of files we want to operate on (the complete path
|
||||
to each file)."""
|
||||
root = self._args.expectations_root
|
||||
regex = re.compile(self._args.builder_name_pattern)
|
||||
return [os.path.join(root, builder, 'expected-results.json')
|
||||
for builder in os.listdir(root)
|
||||
if regex.match(builder)]
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('old_config_name',
|
||||
help=('Config we want to duplicate.'))
|
||||
parser.add_argument('new_config_name',
|
||||
help=('Name of the new config we want to create.'))
|
||||
parser.add_argument('builder_name_pattern',
|
||||
help=('Regex pattern describing which builders we want '
|
||||
'to make the duplication for; \'.*\' to perform '
|
||||
'the duplication on all builders.'))
|
||||
parser.add_argument('--expectations-root',
|
||||
default=DEFAULT_EXPECTATIONS_ROOT,
|
||||
help=('Root of the GM expectations dir; defaults to '
|
||||
'%(default)s'))
|
||||
args = parser.parse_args()
|
||||
copier = Copier(args)
|
||||
copier.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
114
gm/display_json_results.py
Normal file
114
gm/display_json_results.py
Normal file
@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Utility to display a summary of JSON-format GM results, and exit with
|
||||
a nonzero errorcode if there were non-ignored failures in the GM results.
|
||||
|
||||
Usage:
|
||||
python display_json_results.py <filename>
|
||||
|
||||
TODO(epoger): We may want to add flags to set the following:
|
||||
- which error types cause a nonzero return code
|
||||
- maximum number of tests to list for any one ResultAccumulator
|
||||
(to keep the output reasonably short)
|
||||
"""
|
||||
|
||||
__author__ = 'Elliot Poger'
|
||||
|
||||
|
||||
# system-level imports
|
||||
import sys
|
||||
|
||||
# local imports
|
||||
import gm_json
|
||||
|
||||
|
||||
class ResultAccumulator(object):
|
||||
"""Object that accumulates results of a given type, and can generate a
|
||||
summary upon request."""
|
||||
|
||||
def __init__(self, name, do_list, do_fail):
|
||||
"""name: name of the category this result type falls into
|
||||
do_list: whether to list all of the tests with this results type
|
||||
do_fail: whether to return with nonzero exit code if there are any
|
||||
results of this type
|
||||
"""
|
||||
self._name = name
|
||||
self._do_list = do_list
|
||||
self._do_fail = do_fail
|
||||
self._testnames = []
|
||||
|
||||
def AddResult(self, testname):
|
||||
"""Adds a result of this particular type.
|
||||
testname: (string) name of the test"""
|
||||
self._testnames.append(testname)
|
||||
|
||||
def ShouldSignalFailure(self):
|
||||
"""Returns true if this result type is serious (self._do_fail is True)
|
||||
and there were any results of this type."""
|
||||
if self._do_fail and self._testnames:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def GetSummaryLine(self):
|
||||
"""Returns a single-line string summary of all results added to this
|
||||
accumulator so far."""
|
||||
summary = ''
|
||||
if self._do_fail:
|
||||
summary += '[*] '
|
||||
else:
|
||||
summary += '[ ] '
|
||||
summary += str(len(self._testnames))
|
||||
summary += ' '
|
||||
summary += self._name
|
||||
if self._do_list:
|
||||
summary += ': '
|
||||
for testname in self._testnames:
|
||||
summary += testname
|
||||
summary += ' '
|
||||
return summary
|
||||
|
||||
|
||||
def Display(filepath):
|
||||
"""Displays a summary of the results in a JSON file.
|
||||
Returns True if the results are free of any significant failures.
|
||||
filepath: (string) path to JSON file"""
|
||||
|
||||
# Map labels within the JSON file to the ResultAccumulator for each label.
|
||||
results_map = {
|
||||
gm_json.JSONKEY_ACTUALRESULTS_FAILED:
|
||||
ResultAccumulator(name='ExpectationsMismatch',
|
||||
do_list=True, do_fail=True),
|
||||
gm_json.JSONKEY_ACTUALRESULTS_FAILUREIGNORED:
|
||||
ResultAccumulator(name='IgnoredExpectationsMismatch',
|
||||
do_list=True, do_fail=False),
|
||||
gm_json.JSONKEY_ACTUALRESULTS_NOCOMPARISON:
|
||||
ResultAccumulator(name='MissingExpectations',
|
||||
do_list=False, do_fail=False),
|
||||
gm_json.JSONKEY_ACTUALRESULTS_SUCCEEDED:
|
||||
ResultAccumulator(name='Passed',
|
||||
do_list=False, do_fail=False),
|
||||
}
|
||||
|
||||
success = True
|
||||
json_dict = gm_json.LoadFromFile(filepath)
|
||||
actual_results = json_dict[gm_json.JSONKEY_ACTUALRESULTS]
|
||||
for label, accumulator in results_map.iteritems():
|
||||
results = actual_results[label]
|
||||
if results:
|
||||
for result in results:
|
||||
accumulator.AddResult(result)
|
||||
print accumulator.GetSummaryLine()
|
||||
if accumulator.ShouldSignalFailure():
|
||||
success = False
|
||||
print '(results marked with [*] will cause nonzero return value)'
|
||||
return success
|
||||
|
||||
|
||||
if '__main__' == __name__:
|
||||
if len(sys.argv) != 2:
|
||||
raise Exception('usage: %s <input-json-filepath>' % sys.argv[0])
|
||||
sys.exit(0 if Display(sys.argv[1]) else 1)
|
163
gm/gm_error.h
Normal file
163
gm/gm_error.h
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Error codes used by gmmain.cpp.
|
||||
*/
|
||||
|
||||
#ifndef gm_error_DEFINED
|
||||
#define gm_error_DEFINED
|
||||
|
||||
#include "gm.h"
|
||||
|
||||
namespace skiagm {
|
||||
|
||||
/**
|
||||
* The complete list of error types we might encounter in GM.
|
||||
*/
|
||||
enum ErrorType {
|
||||
// Even though kNoGpuContext_ErrorType only occurs when SK_SUPPORT_GPU
|
||||
// is turned on, we always include this type in our enum so that
|
||||
// reports will be consistent whether SK_SUPPORT_GPU is turned on
|
||||
// or off (as long as the number of these errors is 0).
|
||||
kNoGpuContext_ErrorType,
|
||||
|
||||
kIntentionallySkipped_ErrorType,
|
||||
kRenderModeMismatch_ErrorType,
|
||||
kGeneratePdfFailed_ErrorType,
|
||||
kExpectationsMismatch_ErrorType,
|
||||
kMissingExpectations_ErrorType,
|
||||
kWritingReferenceImage_ErrorType,
|
||||
kLast_ErrorType = kWritingReferenceImage_ErrorType
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the name of the given ErrorType.
|
||||
*/
|
||||
static const char *getErrorTypeName(ErrorType type) {
|
||||
switch(type) {
|
||||
case kNoGpuContext_ErrorType:
|
||||
return "NoGpuContext";
|
||||
case kIntentionallySkipped_ErrorType:
|
||||
return "IntentionallySkipped";
|
||||
case kRenderModeMismatch_ErrorType:
|
||||
return "RenderModeMismatch";
|
||||
case kGeneratePdfFailed_ErrorType:
|
||||
return "GeneratePdfFailed";
|
||||
case kExpectationsMismatch_ErrorType:
|
||||
return "ExpectationsMismatch";
|
||||
case kMissingExpectations_ErrorType:
|
||||
return "MissingExpectations";
|
||||
case kWritingReferenceImage_ErrorType:
|
||||
return "WritingReferenceImage";
|
||||
}
|
||||
// control should never reach here
|
||||
SkDEBUGFAIL("getErrorTypeName() called with unknown type");
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills in "type" with the ErrorType associated with name "name".
|
||||
* Returns true if we found one, false if it is an unknown type name.
|
||||
*/
|
||||
static bool getErrorTypeByName(const char name[], ErrorType *type) {
|
||||
for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) {
|
||||
ErrorType thisType = static_cast<ErrorType>(typeInt);
|
||||
const char *thisTypeName = getErrorTypeName(thisType);
|
||||
if (0 == strcmp(thisTypeName, name)) {
|
||||
*type = thisType;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A combination of 0 or more ErrorTypes.
|
||||
*/
|
||||
class ErrorCombination {
|
||||
public:
|
||||
ErrorCombination() : fBitfield(0) {}
|
||||
ErrorCombination(const ErrorType type) : fBitfield(1 << type) {}
|
||||
|
||||
/**
|
||||
* Returns true iff there are NO errors.
|
||||
*/
|
||||
bool isEmpty() const {
|
||||
return (0 == this->fBitfield);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds this ErrorType to this ErrorCombination.
|
||||
*/
|
||||
void add(const ErrorType type) {
|
||||
this->fBitfield |= (1 << type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all ErrorTypes in "other" to this ErrorCombination.
|
||||
*/
|
||||
void add(const ErrorCombination other) {
|
||||
this->fBitfield |= other.fBitfield;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff this ErrorCombination includes this ErrorType.
|
||||
*/
|
||||
bool includes(const ErrorType type) const {
|
||||
return !(0 == (this->fBitfield & (1 << type)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of all ErrorTypes in this
|
||||
* ErrorCombination.
|
||||
*
|
||||
* @param separator text with which to separate ErrorType names
|
||||
*/
|
||||
SkString asString(const char separator[]) const {
|
||||
SkString s;
|
||||
for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) {
|
||||
ErrorType type = static_cast<ErrorType>(typeInt);
|
||||
if (this->includes(type)) {
|
||||
if (!s.isEmpty()) {
|
||||
s.append(separator);
|
||||
}
|
||||
s.append(getErrorTypeName(type));
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new ErrorCombination, which includes the union of all
|
||||
* ErrorTypes in two ErrorCombination objects (this and other).
|
||||
*/
|
||||
ErrorCombination plus(const ErrorCombination& other) const {
|
||||
ErrorCombination retval;
|
||||
retval.fBitfield = this->fBitfield | other.fBitfield;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new ErrorCombination, which is a copy of "this"
|
||||
* but with all ErrorTypes in "other" removed.
|
||||
*/
|
||||
ErrorCombination minus(const ErrorCombination& other) const {
|
||||
ErrorCombination retval;
|
||||
retval.fBitfield = this->fBitfield & ~(other.fBitfield);
|
||||
return retval;
|
||||
}
|
||||
|
||||
private:
|
||||
int fBitfield;
|
||||
};
|
||||
|
||||
// No errors at all.
|
||||
const static ErrorCombination kEmpty_ErrorCombination;
|
||||
}
|
||||
|
||||
#endif // ifndef gm_error_DEFINED
|
239
gm/gm_expectations.cpp
Normal file
239
gm/gm_expectations.cpp
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*
|
||||
* TODO(epoger): Combine this with tools/image_expectations.cpp, or eliminate one of the two.
|
||||
*/
|
||||
|
||||
#include "gm_expectations.h"
|
||||
#include "SkBitmapHasher.h"
|
||||
#include "SkData.h"
|
||||
#include "SkImageDecoder.h"
|
||||
|
||||
#define DEBUGFAIL_SEE_STDERR SkDEBUGFAIL("see stderr for message")
|
||||
|
||||
// See gm_json.py for descriptions of each of these JSON keys.
|
||||
// These constants must be kept in sync with the ones in that Python file!
|
||||
const static char kJsonKey_ActualResults[] = "actual-results";
|
||||
const static char kJsonKey_ActualResults_Failed[] = "failed";
|
||||
const static char kJsonKey_ActualResults_FailureIgnored[]= "failure-ignored";
|
||||
const static char kJsonKey_ActualResults_NoComparison[] = "no-comparison";
|
||||
const static char kJsonKey_ActualResults_Succeeded[] = "succeeded";
|
||||
const static char kJsonKey_ExpectedResults[] = "expected-results";
|
||||
const static char kJsonKey_ExpectedResults_AllowedDigests[] = "allowed-digests";
|
||||
const static char kJsonKey_ExpectedResults_IgnoreFailure[] = "ignore-failure";
|
||||
|
||||
// Types of result hashes we support in the JSON file.
|
||||
const static char kJsonKey_Hashtype_Bitmap_64bitMD5[] = "bitmap-64bitMD5";
|
||||
|
||||
|
||||
namespace skiagm {
|
||||
|
||||
Json::Value CreateJsonTree(Json::Value expectedResults,
|
||||
Json::Value actualResultsFailed,
|
||||
Json::Value actualResultsFailureIgnored,
|
||||
Json::Value actualResultsNoComparison,
|
||||
Json::Value actualResultsSucceeded) {
|
||||
Json::Value actualResults;
|
||||
actualResults[kJsonKey_ActualResults_Failed] = actualResultsFailed;
|
||||
actualResults[kJsonKey_ActualResults_FailureIgnored] = actualResultsFailureIgnored;
|
||||
actualResults[kJsonKey_ActualResults_NoComparison] = actualResultsNoComparison;
|
||||
actualResults[kJsonKey_ActualResults_Succeeded] = actualResultsSucceeded;
|
||||
Json::Value root;
|
||||
root[kJsonKey_ActualResults] = actualResults;
|
||||
root[kJsonKey_ExpectedResults] = expectedResults;
|
||||
return root;
|
||||
}
|
||||
|
||||
// GmResultDigest class...
|
||||
|
||||
GmResultDigest::GmResultDigest(const SkBitmap &bitmap) {
|
||||
fIsValid = SkBitmapHasher::ComputeDigest(bitmap, &fHashDigest);
|
||||
}
|
||||
|
||||
GmResultDigest::GmResultDigest(const Json::Value &jsonTypeValuePair) {
|
||||
fIsValid = false;
|
||||
if (!jsonTypeValuePair.isArray()) {
|
||||
SkDebugf("found non-array json value when parsing GmResultDigest: %s\n",
|
||||
jsonTypeValuePair.toStyledString().c_str());
|
||||
DEBUGFAIL_SEE_STDERR;
|
||||
} else if (2 != jsonTypeValuePair.size()) {
|
||||
SkDebugf("found json array with wrong size when parsing GmResultDigest: %s\n",
|
||||
jsonTypeValuePair.toStyledString().c_str());
|
||||
DEBUGFAIL_SEE_STDERR;
|
||||
} else {
|
||||
// TODO(epoger): The current implementation assumes that the
|
||||
// result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
|
||||
Json::Value jsonHashValue = jsonTypeValuePair[1];
|
||||
if (!jsonHashValue.isIntegral()) {
|
||||
SkDebugf("found non-integer jsonHashValue when parsing GmResultDigest: %s\n",
|
||||
jsonTypeValuePair.toStyledString().c_str());
|
||||
DEBUGFAIL_SEE_STDERR;
|
||||
} else {
|
||||
fHashDigest = jsonHashValue.asUInt64();
|
||||
fIsValid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GmResultDigest::isValid() const {
|
||||
return fIsValid;
|
||||
}
|
||||
|
||||
bool GmResultDigest::equals(const GmResultDigest &other) const {
|
||||
// TODO(epoger): The current implementation assumes that this
|
||||
// and other are always of type kJsonKey_Hashtype_Bitmap_64bitMD5
|
||||
return (this->fIsValid && other.fIsValid && (this->fHashDigest == other.fHashDigest));
|
||||
}
|
||||
|
||||
Json::Value GmResultDigest::asJsonTypeValuePair() const {
|
||||
// TODO(epoger): The current implementation assumes that the
|
||||
// result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
|
||||
Json::Value jsonTypeValuePair;
|
||||
if (fIsValid) {
|
||||
jsonTypeValuePair.append(Json::Value(kJsonKey_Hashtype_Bitmap_64bitMD5));
|
||||
jsonTypeValuePair.append(Json::UInt64(fHashDigest));
|
||||
} else {
|
||||
jsonTypeValuePair.append(Json::Value("INVALID"));
|
||||
}
|
||||
return jsonTypeValuePair;
|
||||
}
|
||||
|
||||
SkString GmResultDigest::getHashType() const {
|
||||
// TODO(epoger): The current implementation assumes that the
|
||||
// result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
|
||||
return SkString(kJsonKey_Hashtype_Bitmap_64bitMD5);
|
||||
}
|
||||
|
||||
SkString GmResultDigest::getDigestValue() const {
|
||||
// TODO(epoger): The current implementation assumes that the
|
||||
// result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
|
||||
SkString retval;
|
||||
retval.appendU64(fHashDigest);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
// Expectations class...
|
||||
|
||||
Expectations::Expectations(bool ignoreFailure) {
|
||||
fIgnoreFailure = ignoreFailure;
|
||||
}
|
||||
|
||||
Expectations::Expectations(const SkBitmap& bitmap, bool ignoreFailure) {
|
||||
fBitmap = bitmap;
|
||||
fIgnoreFailure = ignoreFailure;
|
||||
fAllowedResultDigests.push_back(GmResultDigest(bitmap));
|
||||
}
|
||||
|
||||
Expectations::Expectations(const BitmapAndDigest& bitmapAndDigest) {
|
||||
fBitmap = bitmapAndDigest.fBitmap;
|
||||
fIgnoreFailure = false;
|
||||
fAllowedResultDigests.push_back(bitmapAndDigest.fDigest);
|
||||
}
|
||||
|
||||
Expectations::Expectations(Json::Value jsonElement) {
|
||||
if (jsonElement.empty()) {
|
||||
fIgnoreFailure = kDefaultIgnoreFailure;
|
||||
} else {
|
||||
Json::Value ignoreFailure = jsonElement[kJsonKey_ExpectedResults_IgnoreFailure];
|
||||
if (ignoreFailure.isNull()) {
|
||||
fIgnoreFailure = kDefaultIgnoreFailure;
|
||||
} else if (!ignoreFailure.isBool()) {
|
||||
SkDebugf("found non-boolean json value for key '%s' in element '%s'\n",
|
||||
kJsonKey_ExpectedResults_IgnoreFailure,
|
||||
jsonElement.toStyledString().c_str());
|
||||
DEBUGFAIL_SEE_STDERR;
|
||||
fIgnoreFailure = kDefaultIgnoreFailure;
|
||||
} else {
|
||||
fIgnoreFailure = ignoreFailure.asBool();
|
||||
}
|
||||
|
||||
Json::Value allowedDigests = jsonElement[kJsonKey_ExpectedResults_AllowedDigests];
|
||||
if (allowedDigests.isNull()) {
|
||||
// ok, we'll just assume there aren't any AllowedDigests to compare against
|
||||
} else if (!allowedDigests.isArray()) {
|
||||
SkDebugf("found non-array json value for key '%s' in element '%s'\n",
|
||||
kJsonKey_ExpectedResults_AllowedDigests,
|
||||
jsonElement.toStyledString().c_str());
|
||||
DEBUGFAIL_SEE_STDERR;
|
||||
} else {
|
||||
for (Json::ArrayIndex i=0; i<allowedDigests.size(); i++) {
|
||||
fAllowedResultDigests.push_back(GmResultDigest(allowedDigests[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Expectations::match(GmResultDigest actualGmResultDigest) const {
|
||||
for (int i=0; i < this->fAllowedResultDigests.count(); i++) {
|
||||
GmResultDigest allowedResultDigest = this->fAllowedResultDigests[i];
|
||||
if (allowedResultDigest.equals(actualGmResultDigest)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Json::Value Expectations::asJsonValue() const {
|
||||
Json::Value allowedDigestArray;
|
||||
if (!this->fAllowedResultDigests.empty()) {
|
||||
for (int i=0; i < this->fAllowedResultDigests.count(); i++) {
|
||||
allowedDigestArray.append(this->fAllowedResultDigests[i].asJsonTypeValuePair());
|
||||
}
|
||||
}
|
||||
|
||||
Json::Value jsonExpectations;
|
||||
jsonExpectations[kJsonKey_ExpectedResults_AllowedDigests] = allowedDigestArray;
|
||||
jsonExpectations[kJsonKey_ExpectedResults_IgnoreFailure] = this->ignoreFailure();
|
||||
return jsonExpectations;
|
||||
}
|
||||
|
||||
// IndividualImageExpectationsSource class...
|
||||
|
||||
Expectations IndividualImageExpectationsSource::get(const char *testName) const {
|
||||
SkString path = SkOSPath::Join(fRootDir.c_str(), testName);
|
||||
SkBitmap referenceBitmap;
|
||||
bool decodedReferenceBitmap =
|
||||
SkImageDecoder::DecodeFile(path.c_str(), &referenceBitmap, kN32_SkColorType,
|
||||
SkImageDecoder::kDecodePixels_Mode, NULL);
|
||||
if (decodedReferenceBitmap) {
|
||||
return Expectations(referenceBitmap);
|
||||
} else {
|
||||
return Expectations();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// JsonExpectationsSource class...
|
||||
|
||||
JsonExpectationsSource::JsonExpectationsSource(const char *jsonPath) {
|
||||
Parse(jsonPath, &fJsonRoot);
|
||||
fJsonExpectedResults = fJsonRoot[kJsonKey_ExpectedResults];
|
||||
}
|
||||
|
||||
Expectations JsonExpectationsSource::get(const char *testName) const {
|
||||
return Expectations(fJsonExpectedResults[testName]);
|
||||
}
|
||||
|
||||
/*static*/ bool JsonExpectationsSource::Parse(const char *jsonPath, Json::Value *jsonRoot) {
|
||||
SkAutoDataUnref dataRef(SkData::NewFromFileName(jsonPath));
|
||||
if (NULL == dataRef.get()) {
|
||||
SkDebugf("error reading JSON file %s\n", jsonPath);
|
||||
DEBUGFAIL_SEE_STDERR;
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *bytes = reinterpret_cast<const char *>(dataRef.get()->data());
|
||||
size_t size = dataRef.get()->size();
|
||||
Json::Reader reader;
|
||||
if (!reader.parse(bytes, bytes+size, *jsonRoot)) {
|
||||
SkDebugf("error parsing JSON file %s\n", jsonPath);
|
||||
DEBUGFAIL_SEE_STDERR;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
193
gm/gm_json.py
Normal file
193
gm/gm_json.py
Normal file
@ -0,0 +1,193 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Schema of the JSON summary file written out by the GM tool.
|
||||
|
||||
This must be kept in sync with the kJsonKey_ constants in gm_expectations.cpp !
|
||||
"""
|
||||
|
||||
__author__ = 'Elliot Poger'
|
||||
|
||||
|
||||
# system-level imports
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import posixpath
|
||||
import re
|
||||
|
||||
|
||||
# Key strings used in GM results JSON files (both expected-results.json and
|
||||
# actual-results.json).
|
||||
#
|
||||
# NOTE: These constants must be kept in sync with the kJsonKey_ constants in
|
||||
# gm_expectations.cpp and tools/PictureRenderer.cpp !
|
||||
# Eric suggests: create gm/gm_expectations_constants.h containing ONLY variable
|
||||
# declarations so as to be readable by both gm/gm_expectations.cpp and Python.
|
||||
|
||||
|
||||
JSONKEY_ACTUALRESULTS = 'actual-results'
|
||||
|
||||
# Tests whose results failed to match expectations.
|
||||
JSONKEY_ACTUALRESULTS_FAILED = 'failed'
|
||||
|
||||
# Tests whose results failed to match expectations, but IGNOREFAILURE causes
|
||||
# us to take them less seriously.
|
||||
JSONKEY_ACTUALRESULTS_FAILUREIGNORED = 'failure-ignored'
|
||||
|
||||
# Tests for which we do not have any expectations. They may be new tests that
|
||||
# we haven't had a chance to check in expectations for yet, or we may have
|
||||
# consciously decided to leave them without expectations because we are unhappy
|
||||
# with the results (although we should try to move away from that, and instead
|
||||
# check in expectations with the IGNOREFAILURE flag set).
|
||||
JSONKEY_ACTUALRESULTS_NOCOMPARISON = 'no-comparison'
|
||||
|
||||
# Tests whose results matched their expectations.
|
||||
JSONKEY_ACTUALRESULTS_SUCCEEDED = 'succeeded'
|
||||
|
||||
|
||||
# Descriptions of the result set as a whole.
|
||||
JSONKEY_DESCRIPTIONS = 'descriptions'
|
||||
JSONKEY_DESCRIPTIONS_BUILDER = 'builder'
|
||||
JSONKEY_DESCRIPTIONS_RENDER_MODE = 'renderMode'
|
||||
|
||||
JSONKEY_EXPECTEDRESULTS = 'expected-results'
|
||||
|
||||
# One or more [HashType/DigestValue] pairs representing valid results for this
|
||||
# test. Typically, there will just be one pair, but we allow for multiple
|
||||
# expectations, and the test will pass if any one of them is matched.
|
||||
JSONKEY_EXPECTEDRESULTS_ALLOWEDDIGESTS = 'allowed-digests'
|
||||
|
||||
# Optional: one or more integers listing Skia bugs (under
|
||||
# https://code.google.com/p/skia/issues/list ) that pertain to this expectation.
|
||||
JSONKEY_EXPECTEDRESULTS_BUGS = 'bugs'
|
||||
|
||||
# If IGNOREFAILURE is set to True, a failure of this test will be reported
|
||||
# within the FAILUREIGNORED section (thus NOT causing the buildbots to go red)
|
||||
# rather than the FAILED section (which WOULD cause the buildbots to go red).
|
||||
JSONKEY_EXPECTEDRESULTS_IGNOREFAILURE = 'ignore-failure'
|
||||
|
||||
# Optional: a free-form text string with human-readable information about
|
||||
# this expectation.
|
||||
JSONKEY_EXPECTEDRESULTS_NOTES = 'notes'
|
||||
|
||||
# Optional: boolean indicating whether this expectation was reviewed/approved
|
||||
# by a human being.
|
||||
# If True: a human looked at this image and approved it.
|
||||
# If False: this expectation was committed blind. (In such a case, please
|
||||
# add notes indicating why!)
|
||||
# If absent: this expectation was committed by a tool that didn't enforce human
|
||||
# review of expectations.
|
||||
JSONKEY_EXPECTEDRESULTS_REVIEWED = 'reviewed-by-human'
|
||||
|
||||
# Allowed hash types for test expectations.
|
||||
JSONKEY_HASHTYPE_BITMAP_64BITMD5 = 'bitmap-64bitMD5'
|
||||
|
||||
JSONKEY_HEADER = 'header'
|
||||
JSONKEY_HEADER_TYPE = 'type'
|
||||
JSONKEY_HEADER_REVISION = 'revision'
|
||||
JSONKEY_IMAGE_CHECKSUMALGORITHM = 'checksumAlgorithm'
|
||||
JSONKEY_IMAGE_CHECKSUMVALUE = 'checksumValue'
|
||||
JSONKEY_IMAGE_COMPARISONRESULT = 'comparisonResult'
|
||||
JSONKEY_IMAGE_FILEPATH = 'filepath'
|
||||
JSONKEY_SOURCE_TILEDIMAGES = 'tiled-images'
|
||||
JSONKEY_SOURCE_WHOLEIMAGE = 'whole-image'
|
||||
JSONKEY_IMAGE_BASE_GS_URL = 'image-base-gs-url'
|
||||
|
||||
|
||||
# Root directory where the buildbots store their actually-generated images...
|
||||
# as a publicly readable HTTP URL:
|
||||
GM_ACTUALS_ROOT_HTTP_URL = (
|
||||
'http://chromium-skia-gm.commondatastorage.googleapis.com/gm')
|
||||
# as a GS URL that allows credential-protected write access:
|
||||
GM_ACTUALS_ROOT_GS_URL = 'gs://chromium-skia-gm/gm'
|
||||
|
||||
# Pattern used to assemble each image's filename
|
||||
IMAGE_FILENAME_PATTERN = '(.+)_(.+)\.png' # matches (testname, config)
|
||||
|
||||
# Pattern used to create image URLs, relative to some base URL.
|
||||
GM_RELATIVE_URL_FORMATTER = '%s/%s/%s.png' # pass in (hash_type, test_name,
|
||||
# hash_digest)
|
||||
GM_RELATIVE_URL_PATTERN = '(.+)/(.+)/(.+).png' # matches (hash_type, test_name,
|
||||
# hash_digest)
|
||||
GM_RELATIVE_URL_RE = re.compile(GM_RELATIVE_URL_PATTERN)
|
||||
|
||||
|
||||
def CreateGmActualUrl(test_name, hash_type, hash_digest,
|
||||
gm_actuals_root_url=GM_ACTUALS_ROOT_HTTP_URL):
|
||||
"""Return the URL we can use to download a particular version of
|
||||
the actually-generated image for this particular GM test.
|
||||
|
||||
test_name: name of the test, e.g. 'perlinnoise'
|
||||
hash_type: string indicating the hash type used to generate hash_digest,
|
||||
e.g. JSONKEY_HASHTYPE_BITMAP_64BITMD5
|
||||
hash_digest: the hash digest of the image to retrieve
|
||||
gm_actuals_root_url: root url where actual images are stored
|
||||
"""
|
||||
return posixpath.join(
|
||||
gm_actuals_root_url, CreateGmRelativeUrl(
|
||||
test_name=test_name, hash_type=hash_type, hash_digest=hash_digest))
|
||||
|
||||
|
||||
def CreateGmRelativeUrl(test_name, hash_type, hash_digest):
|
||||
"""Returns a relative URL pointing at a test result's image.
|
||||
|
||||
Returns the URL we can use to download a particular version of
|
||||
the actually-generated image for this particular GM test,
|
||||
relative to the URL root.
|
||||
|
||||
Args:
|
||||
test_name: name of the test, e.g. 'perlinnoise'
|
||||
hash_type: string indicating the hash type used to generate hash_digest,
|
||||
e.g. JSONKEY_HASHTYPE_BITMAP_64BITMD5
|
||||
hash_digest: the hash digest of the image to retrieve
|
||||
"""
|
||||
return GM_RELATIVE_URL_FORMATTER % (hash_type, test_name, hash_digest)
|
||||
|
||||
|
||||
def SplitGmRelativeUrl(url):
|
||||
"""Splits the relative URL into (test_name, hash_type, hash_digest) tuple.
|
||||
|
||||
This is the inverse of CreateGmRelativeUrl().
|
||||
|
||||
Args:
|
||||
url: a URL generated with CreateGmRelativeUrl().
|
||||
|
||||
Returns: (test_name, hash_type, hash_digest) tuple.
|
||||
"""
|
||||
hash_type, test_name, hash_digest = GM_RELATIVE_URL_RE.match(url).groups()
|
||||
return (test_name, hash_type, hash_digest)
|
||||
|
||||
|
||||
def LoadFromString(file_contents):
|
||||
"""Loads the JSON summary written out by the GM tool.
|
||||
|
||||
Returns a dictionary keyed by the values listed as JSONKEY_ constants
|
||||
above; if file_contents is empty, returns None."""
|
||||
# TODO(epoger): we should add a version number to the JSON file to ensure
|
||||
# that the writer and reader agree on the schema (raising an exception
|
||||
# otherwise).
|
||||
if not file_contents:
|
||||
return None
|
||||
json_dict = json.loads(file_contents)
|
||||
return json_dict
|
||||
|
||||
|
||||
def LoadFromFile(file_path):
|
||||
"""Loads the JSON summary written out by the GM tool.
|
||||
Returns a dictionary keyed by the values listed as JSONKEY_ constants
|
||||
above."""
|
||||
file_contents = open(file_path, 'r').read()
|
||||
return LoadFromString(file_contents)
|
||||
|
||||
|
||||
def WriteToFile(json_dict, file_path):
|
||||
"""Writes the JSON summary in json_dict out to file_path.
|
||||
|
||||
The file is written Unix-style (each line ends with just LF, not CRLF);
|
||||
see https://code.google.com/p/skia/issues/detail?id=1815 for reasons."""
|
||||
with io.open(file_path, mode='w', newline='', encoding='utf-8') as outfile:
|
||||
outfile.write(unicode(json.dumps(json_dict, outfile, sort_keys=True,
|
||||
indent=2)))
|
2549
gm/gmmain.cpp
Normal file
2549
gm/gmmain.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1
gm/rebaseline_server/__init__.py
Normal file
1
gm/rebaseline_server/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
# Needed so that test_all.py will recurse into this directory.
|
41
gm/rebaseline_server/base_unittest.py
Executable file
41
gm/rebaseline_server/base_unittest.py
Executable file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
"""
|
||||
Copyright 2014 Google Inc.
|
||||
|
||||
Use of this source code is governed by a BSD-style license that can be
|
||||
found in the LICENSE file.
|
||||
|
||||
A wrapper around the standard Python unittest library, adding features we need
|
||||
for various unittests within this directory.
|
||||
"""
|
||||
|
||||
# System-level imports.
|
||||
import os
|
||||
import sys
|
||||
|
||||
PARENT_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
TRUNK_DIR = os.path.abspath(os.path.join(PARENT_DIR, os.pardir, os.pardir))
|
||||
|
||||
# Import the superclass base_unittest module from the tools dir.
|
||||
#
|
||||
# TODO(epoger): If I don't put this at the beginning of sys.path, the import of
|
||||
# tests.base_unittest fails. That's bad. I need to come up with a cleaner way
|
||||
# of doing this... I think this will involve changing how we import the "boto"
|
||||
# library in gs_utils.py, within the common repo.
|
||||
TOOLS_DIR = os.path.join(TRUNK_DIR, 'tools')
|
||||
if TOOLS_DIR != sys.path[0]:
|
||||
sys.path.insert(0, TOOLS_DIR)
|
||||
import tests.base_unittest as superclass_module
|
||||
|
||||
|
||||
class TestCase(superclass_module.TestCase):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(TestCase, self).__init__(*args, **kwargs)
|
||||
# Some of the tests within this package want their output validated,
|
||||
# so we declare where the expected and actual output will be.
|
||||
self._testdata_dir = os.path.join(PARENT_DIR, 'testdata')
|
||||
|
||||
def main(*args, **kwargs):
|
||||
superclass_module.main(*args, **kwargs)
|
70
gm/rebaseline_server/column.py
Normal file
70
gm/rebaseline_server/column.py
Normal file
@ -0,0 +1,70 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
"""
|
||||
Copyright 2014 Google Inc.
|
||||
|
||||
Use of this source code is governed by a BSD-style license that can be
|
||||
found in the LICENSE file.
|
||||
|
||||
ColumnHeaderFactory class (see class docstring for details)
|
||||
"""
|
||||
|
||||
# Keys used within dictionary representation of each column header.
|
||||
# NOTE: Keep these in sync with static/constants.js
|
||||
KEY__EXTRACOLUMNHEADERS__HEADER_TEXT = 'headerText'
|
||||
KEY__EXTRACOLUMNHEADERS__HEADER_URL = 'headerUrl'
|
||||
KEY__EXTRACOLUMNHEADERS__IS_FILTERABLE = 'isFilterable'
|
||||
KEY__EXTRACOLUMNHEADERS__IS_SORTABLE = 'isSortable'
|
||||
KEY__EXTRACOLUMNHEADERS__USE_FREEFORM_FILTER = 'useFreeformFilter'
|
||||
KEY__EXTRACOLUMNHEADERS__VALUES_AND_COUNTS = 'valuesAndCounts'
|
||||
|
||||
|
||||
class ColumnHeaderFactory(object):
|
||||
"""Factory which assembles the header for a single column of data."""
|
||||
|
||||
def __init__(self, header_text, header_url=None,
|
||||
is_filterable=True, is_sortable=True,
|
||||
use_freeform_filter=False):
|
||||
"""
|
||||
Args:
|
||||
header_text: string; text the client should display within column header.
|
||||
header_url: string; target URL if user clicks on column header.
|
||||
If None, nothing to click on.
|
||||
is_filterable: boolean; whether client should allow filtering on this
|
||||
column.
|
||||
is_sortable: boolean; whether client should allow sorting on this column.
|
||||
use_freeform_filter: boolean; *recommendation* to the client indicating
|
||||
whether to allow freeform text matching, as opposed to listing all
|
||||
values alongside checkboxes. If is_filterable==false, this is
|
||||
meaningless.
|
||||
"""
|
||||
self._header_text = header_text
|
||||
self._header_url = header_url
|
||||
self._is_filterable = is_filterable
|
||||
self._is_sortable = is_sortable
|
||||
self._use_freeform_filter = use_freeform_filter
|
||||
|
||||
def create_as_dict(self, values_and_counts_dict=None):
|
||||
"""Creates the header for this column, in dictionary form.
|
||||
|
||||
Creates the header for this column in dictionary form, as needed when
|
||||
constructing the JSON representation. Uses the KEY__EXTRACOLUMNHEADERS__*
|
||||
constants as keys.
|
||||
|
||||
Args:
|
||||
values_and_counts_dict: dictionary mapping each possible column value
|
||||
to its count (how many entries in the column have this value), or
|
||||
None if this information is not available.
|
||||
"""
|
||||
asdict = {
|
||||
KEY__EXTRACOLUMNHEADERS__HEADER_TEXT: self._header_text,
|
||||
KEY__EXTRACOLUMNHEADERS__IS_FILTERABLE: self._is_filterable,
|
||||
KEY__EXTRACOLUMNHEADERS__IS_SORTABLE: self._is_sortable,
|
||||
KEY__EXTRACOLUMNHEADERS__USE_FREEFORM_FILTER: self._use_freeform_filter,
|
||||
}
|
||||
if self._header_url:
|
||||
asdict[KEY__EXTRACOLUMNHEADERS__HEADER_URL] = self._header_url
|
||||
if values_and_counts_dict:
|
||||
asdict[KEY__EXTRACOLUMNHEADERS__VALUES_AND_COUNTS] = sorted(
|
||||
values_and_counts_dict.items())
|
||||
return asdict
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user