blob: 2e6c37f145117365d8f2dda782f2ff39d3f118cb (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
|
# compress-and-verify.cmake -- Runs a test against an input file to make sure that the specified
# targets are able to to compress and then decompress successfully. Optionally verify
# the results with gzip. Output files are generated with unique names to prevent parallel
# tests from corrupting one another. Default target arguments are compatible with minigzip.
# Copyright (C) 2021 Nathan Moinvaziri
# Licensed under the Zlib license, see LICENSE.md for details
# that test a specific input file for compression or decompression.
# Required Variables
# INPUT - Input file to test
# TARGET or - Command to run for both compress and decompress
# COMPRESS_TARGET and - Command to run to compress input file
# DECOMPRESS_TARGET - Command to run to decompress output file
# Optional Variables
# TEST_NAME - Name of test to use when constructing output file paths
# COMPRESS_ARGS - Arguments to pass for compress command (default: -c -k)
# DECOMPRESS_ARGS - Arguments to pass to decompress command (default: -d -c)
# GZIP_VERIFY - Verify that gzip can decompress the COMPRESS_TARGET output and
# verify that DECOMPRESS_TARGET can decompress gzip output of INPUT
# COMPARE - Verify decompressed output is the same as input
# FILEMODE - Pass data to/from (de)compressor using files instead of stdin/stdout
# SUCCESS_EXIT - List of successful exit codes (default: 0, ie: 0;1)
if(TARGET)
set(COMPRESS_TARGET ${TARGET})
set(DECOMPRESS_TARGET ${TARGET})
endif()
if(NOT DEFINED INPUT OR NOT DEFINED COMPRESS_TARGET OR NOT DEFINED DECOMPRESS_TARGET)
message(FATAL_ERROR "Compress test arguments missing")
endif()
# Set default values
if(NOT DEFINED COMPARE)
set(COMPARE ON)
endif()
if(NOT DEFINED FILEMODE)
set(FILEMODE OFF)
endif()
if(NOT DEFINED COMPRESS_ARGS)
set(COMPRESS_ARGS -3 -k)
if(NOT FILEMODE)
list(APPEND COMPRESS_ARGS -c)
endif()
endif()
if(NOT DEFINED DECOMPRESS_ARGS)
set(DECOMPRESS_ARGS -d -k)
if(NOT FILEMODE)
list(APPEND DECOMPRESS_ARGS -c)
endif()
endif()
if(NOT DEFINED GZIP_VERIFY)
set(GZIP_VERIFY ON)
endif()
if(NOT DEFINED SUCCESS_EXIT)
set(SUCCESS_EXIT 0)
endif()
# Use test name from input file name
if(NOT DEFINED TEST_NAME)
get_filename_component(TEST_NAME "${INPUT}" NAME)
endif()
# Generate unique output path so multiple tests can be executed at the same time
string(RANDOM LENGTH 6 UNIQUE_ID)
string(REPLACE "." "-" TEST_NAME "${TEST_NAME}")
set(OUTPUT_BASE "${CMAKE_CURRENT_BINARY_DIR}/Testing/Temporary/${TEST_NAME}-${UNIQUE_ID}")
# Ensure directory exists for output files
get_filename_component(OUTPUT_DIR "${OUTPUT_BASE}" DIRECTORY)
file(MAKE_DIRECTORY "${OUTPUT_DIR}")
# Cleanup temporary files
macro(cleanup_always)
file(GLOB TEMP_FILES ${OUTPUT_BASE}*)
file(REMOVE ${TEMP_FILES})
endmacro()
# Clean up temporary files if not on CI
macro(cleanup)
if(NOT DEFINED ENV{CI})
cleanup_always()
endif()
endmacro()
# Show differences between two files
macro(diff src1 src2)
find_program(XXD xxd)
if(XXD)
find_program(DIFF diff)
if(DIFF)
set(XXD_COMMAND ${XXD} ${src1} ${src1}.hex)
execute_process(COMMAND ${XXD_COMMAND})
set(XXD_COMMAND ${XXD} ${src2} ${src2}.hex)
execute_process(COMMAND ${XXD_COMMAND})
set(DIFF_COMMAND ${DIFF} -u ${src1}.hex ${src2}.hex)
execute_process(COMMAND ${DIFF_COMMAND}
OUTPUT_FILE ${src2}.diff)
file(READ ${src2}.diff DIFF_OUTPUT)
message(STATUS "Diff:\n${DIFF_OUTPUT}")
if(NOT DEFINED ENV{CI})
file(REMOVE ${src1}.hex ${src2}.hex ${src2}.diff)
endif()
endif()
endif()
endmacro()
macro(exec_streams tcmd tsrc tdst)
execute_process(COMMAND ${CMAKE_COMMAND}
"-DCOMMAND=${tcmd}"
-DINPUT=${tsrc}
-DOUTPUT=${tdst}
"-DSUCCESS_EXIT=${SUCCESS_EXIT}"
-P ${CMAKE_CURRENT_LIST_DIR}/run-and-redirect.cmake
RESULT_VARIABLE CMD_RESULT)
endmacro()
macro(exec_files tcmd tsrc)
execute_process(COMMAND
${tcmd} ${tsrc}
RESULT_VARIABLE CMD_RESULT)
endmacro()
# Compress input file
if(NOT EXISTS ${INPUT})
message(FATAL_ERROR "Cannot find compress input: ${INPUT}")
endif()
set(COMPRESS_COMMAND ${COMPRESS_TARGET} ${COMPRESS_ARGS})
set(INPUT_FILE ${OUTPUT_BASE})
# Make CMake copy and rename file in one operation
# The copied file permissions is standard 644 (-rw-r--r--)
if(NOT CMAKE_VERSION VERSION_LESS "3.19")
set(CONFIGURE_NO_SOURCE_PERMISSIONS NO_SOURCE_PERMISSIONS)
endif()
configure_file(${INPUT} ${INPUT_FILE} COPYONLY ${CONFIGURE_NO_SOURCE_PERMISSIONS})
message(STATUS "Compress ${COMPRESS_COMMAND}")
message(STATUS " Source file: ${INPUT}")
message(STATUS " Compression input file: ${INPUT_FILE}")
message(STATUS " Output: ${OUTPUT_BASE}.gz")
if(FILEMODE)
exec_files("${COMPRESS_COMMAND}" "${INPUT_FILE}")
else()
exec_streams("${COMPRESS_COMMAND}" "${INPUT_FILE}" "${OUTPUT_BASE}.gz")
endif()
if(CMD_RESULT)
cleanup()
message(FATAL_ERROR "Compress failed: ${CMD_RESULT}")
endif()
# Decompress output
if(NOT EXISTS ${OUTPUT_BASE}.gz)
cleanup()
message(FATAL_ERROR "Cannot find decompress input: ${OUTPUT_BASE}.gz")
endif()
set(DECOMPRESS_COMMAND ${DECOMPRESS_TARGET} ${DECOMPRESS_ARGS})
message(STATUS "Decompress ${DECOMPRESS_COMMAND}")
message(STATUS " Input: ${OUTPUT_BASE}.gz")
message(STATUS " Output: ${OUTPUT_BASE}")
if(FILEMODE)
exec_files("${DECOMPRESS_COMMAND}" "${OUTPUT_BASE}.gz")
else()
exec_streams("${DECOMPRESS_COMMAND}" "${OUTPUT_BASE}.gz" "${OUTPUT_BASE}")
endif()
if(CMD_RESULT)
cleanup()
message(FATAL_ERROR "Decompress failed: ${CMD_RESULT}")
endif()
if(COMPARE)
message(STATUS "Diff comparison")
message(STATUS " Input: ${INPUT}")
message(STATUS " Output: ${OUTPUT_BASE}")
# Compare decompressed output with original input file
execute_process(COMMAND ${CMAKE_COMMAND}
-E compare_files ${INPUT} ${OUTPUT_BASE}
RESULT_VARIABLE CMD_RESULT)
if(CMD_RESULT)
diff(${INPUT} ${OUTPUT_BASE})
cleanup()
message(FATAL_ERROR "Compare decompress failed: ${CMD_RESULT}")
endif()
endif()
if(GZIP_VERIFY AND NOT "${COMPRESS_ARGS}" MATCHES "-T")
# Transparent writing does not use gzip format
find_program(GZIP gzip)
if(GZIP)
if(NOT EXISTS ${OUTPUT_BASE}.gz)
cleanup()
message(FATAL_ERROR "Cannot find gzip decompress input: ${OUTPUT_BASE}.gz")
endif()
# Check gzip can decompress our compressed output
set(GZ_DECOMPRESS_COMMAND ${GZIP} -d)
message(STATUS "Gzip decompress ${GZ_DECOMPRESS_COMMAND}")
message(STATUS " Input: ${OUTPUT_BASE}.gz")
message(STATUS " Output: ${OUTPUT_BASE}-ungzip")
exec_streams("${GZ_DECOMPRESS_COMMAND}" "${OUTPUT_BASE}.gz" "${OUTPUT_BASE}-ungzip")
if(CMD_RESULT)
cleanup()
message(FATAL_ERROR "Gzip decompress failed: ${CMD_RESULT}")
endif()
# Compare gzip output with original input file
execute_process(COMMAND ${CMAKE_COMMAND}
-E compare_files ${INPUT} ${OUTPUT_BASE}-ungzip
RESULT_VARIABLE CMD_RESULT)
if(CMD_RESULT)
diff(${INPUT} ${OUTPUT_BASE}-ungzip)
cleanup()
message(FATAL_ERROR "Compare gzip decompress failed: ${CMD_RESULT}")
endif()
# Compress input file with gzip
set(GZ_COMPRESS_COMMAND ${GZIP} --stdout)
message(STATUS "Gzip compress ${GZ_COMPRESS_COMMAND}")
message(STATUS " Input: ${INPUT}")
message(STATUS " Output: ${OUTPUT_BASE}-gzip.gz")
exec_streams("${GZ_COMPRESS_COMMAND}" "${INPUT}" "${OUTPUT_BASE}-gzip.gz")
if(CMD_RESULT)
cleanup()
message(FATAL_ERROR "Gzip compress failed: ${CMD_RESULT}")
endif()
if(NOT EXISTS ${OUTPUT_BASE}-gzip.gz)
cleanup()
message(FATAL_ERROR "Cannot find decompress gzip input: ${OUTPUT_BASE}-gzip.gz")
endif()
message(STATUS "Decompress gzip ${DECOMPRESS_COMMAND}")
message(STATUS " Input: ${OUTPUT_BASE}-gzip.gz")
message(STATUS " Output: ${OUTPUT_BASE}-gzip")
# Check decompress target can handle gzip compressed output
if(FILEMODE)
exec_files("${DECOMPRESS_COMMAND}" "${OUTPUT_BASE}-gzip.gz")
else()
exec_streams("${DECOMPRESS_COMMAND}" "${OUTPUT_BASE}-gzip.gz" "${OUTPUT_BASE}-gzip")
endif()
if(CMD_RESULT)
cleanup()
message(FATAL_ERROR "Decompress gzip failed: ${CMD_RESULT}")
endif()
if(COMPARE)
# Compare original input file with gzip decompressed output
execute_process(COMMAND ${CMAKE_COMMAND}
-E compare_files ${INPUT} ${OUTPUT_BASE}-gzip
RESULT_VARIABLE CMD_RESULT)
if(CMD_RESULT)
diff(${INPUT} ${OUTPUT_BASE}-gzip)
cleanup()
message(FATAL_ERROR "Compare decompress gzip failed: ${CMD_RESULT}")
endif()
endif()
endif()
endif()
cleanup_always()
|