summaryrefslogtreecommitdiff
path: root/cmake/test-compress.cmake
blob: 199796d8fee2d7cb83e1d520c238ba13e0a72b96 (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
# test-compress.cmake -- Runs a test against an input file to make sure that the specified
#   targets are able to to compress and then decompress it 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
#   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 COMPRESS_ARGS)
    set(COMPRESS_ARGS -c -k)
endif()
if(NOT DEFINED DECOMPRESS_ARGS)
    set(DECOMPRESS_ARGS -d -c)
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()

# Compress input file
if(NOT EXISTS ${INPUT})
    message(FATAL_ERROR "Cannot find compress input: ${INPUT}")
endif()

set(COMPRESS_COMMAND ${COMPRESS_TARGET} ${COMPRESS_ARGS})

message(STATUS "Compress ${COMPRESS_COMMAND}")
message(STATUS "  Input: ${INPUT}")
message(STATUS "  Output: ${OUTPUT_BASE}.gz")

execute_process(COMMAND ${CMAKE_COMMAND}
    "-DCOMMAND=${COMPRESS_COMMAND}"
    -DINPUT=${INPUT}
    -DOUTPUT=${OUTPUT_BASE}.gz
    "-DSUCCESS_EXIT=${SUCCESS_EXIT}"
    -P ${CMAKE_CURRENT_LIST_DIR}/run-and-redirect.cmake
    RESULT_VARIABLE CMD_RESULT)

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}")

execute_process(COMMAND ${CMAKE_COMMAND}
    "-DCOMMAND=${DECOMPRESS_COMMAND}"
    -DINPUT=${OUTPUT_BASE}.gz
    -DOUTPUT=${OUTPUT_BASE}
    "-DSUCCESS_EXIT=${SUCCESS_EXIT}"
    -P ${CMAKE_CURRENT_LIST_DIR}/run-and-redirect.cmake
    RESULT_VARIABLE CMD_RESULT)

if(CMD_RESULT)
    cleanup()
    message(FATAL_ERROR "Decompress failed: ${CMD_RESULT}")
endif()

if(COMPARE)
    # 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")

        execute_process(COMMAND ${CMAKE_COMMAND}
            "-DCOMMAND=${GZ_DECOMPRESS_COMMAND}"
            -DINPUT=${OUTPUT_BASE}.gz
            -DOUTPUT=${OUTPUT_BASE}-ungzip
            "-DSUCCESS_EXIT=${SUCCESS_EXIT}"
            -P ${CMAKE_CURRENT_LIST_DIR}/run-and-redirect.cmake
            RESULT_VARIABLE CMD_RESULT)

        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")

        execute_process(COMMAND ${CMAKE_COMMAND}
            "-DCOMMAND=${GZ_COMPRESS_COMMAND}"
            -DINPUT=${INPUT}
            -DOUTPUT=${OUTPUT_BASE}-gzip.gz
            "-DSUCCESS_EXIT=${SUCCESS_EXIT}"
            -P ${CMAKE_CURRENT_LIST_DIR}/run-and-redirect.cmake
            RESULT_VARIABLE CMD_RESULT)

        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
        execute_process(COMMAND ${CMAKE_COMMAND}
            "-DCOMMAND=${DECOMPRESS_COMMAND}"
            -DINPUT=${OUTPUT_BASE}-gzip.gz
            -DOUTPUT=${OUTPUT_BASE}-gzip
            "-DSUCCESS_EXIT=${SUCCESS_EXIT}"
            -P ${CMAKE_CURRENT_LIST_DIR}/run-and-redirect.cmake
            RESULT_VARIABLE CMD_RESULT)

        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()