Skip to content

Commit 7911936

Browse files
SiegeLordExSiegeLord
authored andcommitted
Add automatic output tests.
1 parent a7dd0af commit 7911936

File tree

3 files changed

+51
-13
lines changed

3 files changed

+51
-13
lines changed

.github/workflows/continuous-integration.yml

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,38 @@ jobs:
1616
rustup component add rustfmt --toolchain nightly-x86_64-unknown-linux-gnu
1717
- name: Setup
1818
run: |
19-
sudo apt-get install python3-pip --force-yes
20-
sudo pip3 install toml
19+
curl -LsSf https://astral.sh/uv/install.sh | sh
20+
. setup_venv.sh
2121
sudo apt-get install gnuplot
2222
- name: Tests
2323
run: |
24+
. venv/bin/activate
2425
./cargo_util.py --test
2526
./gnuplot/target/debug/examples/example1 --no-show
2627
./gnuplot/target/debug/examples/example2 --no-show
2728
./gnuplot/target/debug/examples/example3 --no-show
2829
./gnuplot/target/debug/examples/example4 --no-show
30+
31+
if [ -n "${{ github.base_ref }}" ]; then
32+
CHANGED_OUTPUTS=$(echo "${{ github.event.pull_request.body }}" | sed -n 's/.*CHANGED_OUTPUTS=\([^ ]*\).*/\1/p')
33+
BASE_BRANCH="${{ github.base_ref }}"
34+
HEAD_BRANCH="${{ github.head_ref || github.ref_name }}"
35+
36+
git fetch origin $BASE_BRANCH
37+
git checkout $BASE_BRANCH
38+
./cargo_util.py --make_golden_outputs
39+
git checkout $HEAD_BRANCH
40+
./cargo_util.py --test_outputs --ignore_new_outputs --changed_outputs $CHANGED_OUTPUTS
41+
fi
42+
- name: Upload golden outputs
43+
if: ${{ always() }}
44+
uses: actions/upload-artifact@v4
45+
with:
46+
name: golden_outputs
47+
path: golden_outputs
48+
- name: Upload test outputs
49+
if: ${{ always() }}
50+
uses: actions/upload-artifact@v4
51+
with:
52+
name: test_outputs
53+
path: test_outputs

cargo_util.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ def split(s):
2525
parser.add_argument('--publish', action='store_true', help='publish the crates')
2626
parser.add_argument('--build', action='store_true', help='build the crates')
2727
parser.add_argument('--test', action='store_true', help='test the crates')
28-
parser.add_argument('--test_outputs', action='store_true', help='run the unittests')
28+
parser.add_argument('--make_golden_outputs', action='store_true', help='make the golden outputs')
29+
parser.add_argument('--test_outputs', action='store_true', help='run the output tests')
30+
parser.add_argument('--ignore_new_outputs', action='store_true', help='whether to ignore new outputs')
31+
parser.add_argument('--changed_outputs', type=str, default='', help='comma separated list of outputs to ignore failures in, e.g. "foo.png,bar.png"')
2932
parser.add_argument('--clean', action='store_true', help='clean the crates')
3033
parser.add_argument('--doc', action='store_true', help='build the documentation')
3134
parser.add_argument('--format', action='store_true', help='format all the non-sys crates')
@@ -95,12 +98,16 @@ def cargo_cmd(*command):
9598
check_call(cargo_cmd('test'), cwd=crate)
9699
check_call(cargo_cmd('fmt', '--check'), cwd=crate)
97100

98-
if args.test_outputs:
101+
if args.test_outputs or args.make_golden_outputs:
99102
import numpy as np
100103
from PIL import Image
101104

102-
os.makedirs('test_outputs', exist_ok=True)
103-
output_dir = os.path.abspath('test_outputs')
105+
if args.test_outputs:
106+
output_dir = 'test_outputs'
107+
else:
108+
output_dir = 'golden_outputs'
109+
os.makedirs(output_dir, exist_ok=True)
110+
output_dir = os.path.abspath(output_dir)
104111
metadata = json.loads(check_output(cargo_cmd('metadata', '--format-version=1', '--no-deps'), cwd='gnuplot').decode('utf8'))
105112
for target in metadata['packages'][0]['targets']:
106113
if target['kind'] != ['example']:
@@ -115,6 +122,9 @@ def cargo_cmd(*command):
115122

116123
check_call(cargo_cmd('run', '--example', target['name'], '--', '--no-show', '--output-dir', output_dir, '--save-png'), cwd='gnuplot')
117124

125+
if args.make_golden_outputs:
126+
exit(0)
127+
118128
golden_images = [pathlib.Path(f) for f in glob.glob('golden_outputs/*.png')]
119129
test_images = [pathlib.Path(f) for f in glob.glob(f'{output_dir}/*.png')]
120130

@@ -123,19 +133,26 @@ def cargo_cmd(*command):
123133
if golden_filenames != test_filenames:
124134
missing = set(golden_filenames) - set(test_filenames)
125135
extra = set(test_filenames) - set(golden_filenames)
126-
assert False, f"Test images don't match golden images.\nExtra: {extra}\nMissing: {missing}"
136+
if not args.ignore_new_outputs or missing:
137+
assert False, f"Test images don't match golden images.\nExtra: {extra}\nMissing: {missing}"
127138

139+
changed_outputs = args.changed_outputs.split(',')
140+
failed = False
128141
for image_name in golden_images:
129142
golden_image_path = pathlib.Path(image_name)
130143
test_image_path = pathlib.Path(output_dir) / golden_image_path.name
131144
assert test_image_path.exists(), f"{test_image_path} not found"
132-
145+
if golden_image_path.name in changed_outputs:
146+
continue
133147
golden_image = np.array(Image.open(golden_image_path)).astype(np.float32)
134148
test_image = np.array(Image.open(test_image_path)).astype(np.float32)
135149
try:
136150
np.testing.assert_allclose(golden_image, test_image, atol=5, err_msg=f"{golden_image_path.resolve()}\n{test_image_path.resolve()}")
137151
except AssertionError as e:
152+
failed = True
138153
print(e)
154+
if failed:
155+
exit(1)
139156

140157

141158
if args.clean:

gnuplot/src/axes2d.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -662,11 +662,7 @@ impl Axes2D
662662
{
663663
let (data, num_rows, num_cols) = generate_data!(options, x, y);
664664
self.common.elems.push(PlotElement::new_plot(
665-
Polygons,
666-
data,
667-
num_rows,
668-
num_cols,
669-
options,
665+
Polygons, data, num_rows, num_cols, options,
670666
));
671667
self
672668
}

0 commit comments

Comments
 (0)