Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ on:
# Trigger the workflow on pull request
pull_request:
paths-ignore:
- "tests/**"
- "data/**"
- "deprecated/**"

Expand Down
21 changes: 19 additions & 2 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,20 @@ list(APPEND test_c_bins
grib_sh_imag
grib_spectral
grib_lam_bf
grib_lam_gp)
grib_lam_gp
test_bits
test_float_conversions
test_value_api
test_expression
test_data_structures
test_geo
test_io
test_trie
test_keys_iterator
test_handle_lifecycle
test_util
test_bufr_descriptors
test_bufr_api)


foreach( tool ${test_c_bins} )
Expand Down Expand Up @@ -184,6 +197,8 @@ if( HAVE_BUILD_TOOLS )
grib_stattype
grib_ecc-2221
grib_ecc-2218
test_unit_extended
grib_corrupted_messages
)

# These tests require data downloads
Expand Down Expand Up @@ -420,7 +435,9 @@ if( HAVE_BUILD_TOOLS )
grib_neg_fctime
codes_split_file
grib_mars_keys1
grib_mars_keys2)
grib_mars_keys2
grib_packing_roundtrip
)

if( HAVE_AEC AND ENABLE_EXTRA_TESTS )
list(APPEND tests_extra grib_ecc-1431)
Expand Down
110 changes: 110 additions & 0 deletions tests/grib_corrupted_messages.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/bin/sh
# (C) Copyright 2005- ECMWF.
#
# This software is licensed under the terms of the Apache Licence Version 2.0
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
#
# In applying this licence, ECMWF does not waive the privileges and immunities granted to it by
# virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction.
#

. ./include.ctest.sh

label="corrupted_messages"

# -----------------------------------------------
# Test that corrupted/truncated GRIB/BUFR messages
# are handled gracefully (no crashes, proper error codes)
# -----------------------------------------------
Comment on lines +11 to +18
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test uses Unix-specific tooling (dd, /dev/urandom, etc.) but has no Windows skip guard. Many other scripts bail out early when $ECCODES_ON_WINDOWS -eq 1; consider adding the same here to avoid breaking Windows CTest runs.

Copilot uses AI. Check for mistakes.

tempGrib=temp.$label.grib
tempBufr=temp.$label.bufr
tempCorrupt=temp.$label.corrupt
tempOut=temp.$label.out

# --- Test 1: Truncated GRIB message ---
echo "Test: Truncated GRIB message..."
${tools_dir}/grib_set -s edition=2 $ECCODES_SAMPLES_PATH/GRIB2.tmpl $tempGrib
size=$(wc -c < $tempGrib | tr -d ' ')
half=$((size / 2))

# Truncate to first half
dd if=$tempGrib of=$tempCorrupt bs=1 count=$half 2>/dev/null
set +e
${tools_dir}/grib_ls $tempCorrupt > $tempOut 2>&1
status=$?
set -e
# Should fail (non-zero exit), not crash
echo "Truncated GRIB: grib_ls exit code=$status"

Comment on lines +33 to +39
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This script captures exit codes for the corrupted/truncated cases but never asserts anything about them. As written, the test will still exit 0 even if grib_ls/bufr_ls unexpectedly succeed on corrupted input or if they crash (segfault/abort) and return a signal-based status. Add explicit checks on $status (e.g. test $status -ne 0 and/or fail on common crash codes like 134/139) so the test can actually fail when behavior regresses.

Copilot uses AI. Check for mistakes.
# --- Test 2: Truncated BUFR message ---
echo "Test: Truncated BUFR message..."
# Copy BUFR sample directly (grib_set cannot handle BUFR files)
cp $ECCODES_SAMPLES_PATH/BUFR4.tmpl $tempBufr
size=$(wc -c < $tempBufr | tr -d ' ')
half=$((size / 2))

dd if=$tempBufr of=$tempCorrupt bs=1 count=$half 2>/dev/null
set +e
${tools_dir}/bufr_ls $tempCorrupt > $tempOut 2>&1
status=$?
set -e
echo "Truncated BUFR: bufr_ls exit code=$status"

# --- Test 3: Corrupted magic number ---
echo "Test: Corrupted magic number..."
cp $tempGrib $tempCorrupt
# Replace first byte 'G' (0x47) with 'X' (0x58)
printf '\x58' | dd of=$tempCorrupt bs=1 count=1 conv=notrunc 2>/dev/null
set +e
${tools_dir}/grib_ls $tempCorrupt > $tempOut 2>&1
status=$?
set -e
echo "Corrupted magic: grib_ls exit code=$status"
# Should fail or report no messages, not crash

# --- Test 4: File with just "GRIB" header and nothing else ---
echo "Test: GRIB header only (4 bytes)..."
printf 'GRIB' > $tempCorrupt
set +e
${tools_dir}/grib_ls $tempCorrupt > $tempOut 2>&1
status=$?
set -e
echo "GRIB header only: grib_ls exit code=$status"

# --- Test 5: Empty file ---
echo "Test: Empty file..."
> $tempCorrupt
set +e
${tools_dir}/grib_ls $tempCorrupt > $tempOut 2>&1
status=$?
set -e
echo "Empty file: grib_ls exit code=$status"

# --- Test 6: Random bytes file ---
echo "Test: Random bytes..."
dd if=/dev/urandom of=$tempCorrupt bs=1 count=256 2>/dev/null
set +e
${tools_dir}/grib_ls $tempCorrupt > $tempOut 2>&1
status=$?
set -e
echo "Random bytes: grib_ls exit code=$status"

# --- Test 7: Missing 7777 end marker ---
echo "Test: Missing 7777 end marker..."
cp $tempGrib $tempCorrupt
size=$(wc -c < $tempCorrupt | tr -d ' ')
truncsize=$((size - 4))
dd if=$tempGrib of=$tempCorrupt bs=1 count=$truncsize 2>/dev/null
# Append something that is NOT 7777
printf '\x00\x00\x00\x00' >> $tempCorrupt
set +e
${tools_dir}/grib_ls $tempCorrupt > $tempOut 2>&1
status=$?
set -e
echo "Bad end marker: grib_ls exit code=$status"

echo ""
echo "All corrupted message tests completed without crashes."

rm -f $tempGrib $tempBufr $tempCorrupt $tempOut
95 changes: 95 additions & 0 deletions tests/grib_packing_roundtrip.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/bin/sh
# (C) Copyright 2005- ECMWF.
#
# This software is licensed under the terms of the Apache Licence Version 2.0
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
#
# In applying this licence, ECMWF does not waive the privileges and immunities granted to it by
# virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction.
#

. ./include.ctest.sh

label="packing_roundtrip"

# -----------------------------------------------
# Test packing round-trip: encode values, decode, compare
# This ensures different packing types preserve data integrity
# -----------------------------------------------
Comment on lines +11 to +18
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like other Unix-heavy test scripts, this one may need an early skip on Windows ($ECCODES_ON_WINDOWS) because it relies on common POSIX utilities (seq, head, wc, redirections) and assumes a Unix-like shell environment.

Copilot uses AI. Check for mistakes.

tempGrib=temp.$label.grib
tempOut=temp.$label.out
tempRef=temp.$label.ref
tempFilt=temp.$label.filt

# Create a GRIB2 message from sample with known grid dimensions
${tools_dir}/grib_set -s Ni=36,Nj=18,numberOfDataPoints=648,numberOfValues=648 \
$ECCODES_SAMPLES_PATH/GRIB2.tmpl $tempGrib

# Generate ascending test values (temperature-like)
cat > $tempFilt << EOF
set bitsPerValue = 16;
set Ni = 36;
set Nj = 18;
set numberOfDataPoints = 648;
set numberOfValues = 648;
# Set values to a ramp from 200 to 320 (temperature range in K)
set values = {$(seq 200 0.1855 320.1 | head -648 | tr '\n' ',' | sed 's/,$//')};
write;
EOF

# Test simple packing (grid_simple) - the default
${tools_dir}/grib_filter -o $tempGrib $tempFilt $ECCODES_SAMPLES_PATH/GRIB2.tmpl
grib_check_key_equals $tempGrib packingType grid_simple

stats=$(${tools_dir}/grib_get -p max,min,avg $tempGrib)
echo "Simple packing stats: $stats"

# Verify we can read back the values
${tools_dir}/grib_get_data $tempGrib > $tempOut
count=$(wc -l < $tempOut | tr -d ' ')
# account for header line
test "$count" -gt 0
Comment on lines +51 to +52
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The grib_get_data output line-count check is effectively a no-op (test "$count" -gt 0). Since this test sets Ni=36,Nj=18 (648 points) and mentions a header line, it should assert the expected number of lines (e.g. 649) to actually validate the round-trip produced the full field.

Suggested change
# account for header line
test "$count" -gt 0
# expect 1 header line + 648 data lines
test "$count" -eq 649

Copilot uses AI. Check for mistakes.

# Test grid_second_order packing if data file is big enough
if [ "$HAVE_AEC" = "1" ]; then
tempCcsds=temp.${label}.ccsds.grib
${tools_dir}/grib_set -s packingType=grid_ccsds $tempGrib $tempCcsds
grib_check_key_equals $tempCcsds packingType grid_ccsds

# Compare original and CCSDS-packed values
val1=$(${tools_dir}/grib_get -p avg $tempGrib)
val2=$(${tools_dir}/grib_get -p avg $tempCcsds)
# They should be close (within packing tolerance)
echo "Simple avg=$val1, CCSDS avg=$val2"
rm -f $tempCcsds
fi

# Test changing bitsPerValue
for bpv in 8 12 16 24; do
tempBpv=temp.${label}.bpv${bpv}.grib
${tools_dir}/grib_set -s bitsPerValue=$bpv $tempGrib $tempBpv
bpv_out=$(${tools_dir}/grib_get -p bitsPerValue $tempBpv)
test "$bpv_out" = "$bpv"
rm -f $tempBpv
done

# Test constant field (all values the same)
cat > $tempFilt << EOF
set bitsPerValue = 16;
set Ni = 10;
set Nj = 10;
set numberOfDataPoints = 100;
set numberOfValues = 100;
set values = {$(python3 -c "print(','.join(['273.15']*100))")};
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test generates the constant field values via python3 -c ..., introducing a new runtime dependency on Python for this shell test. Other existing tests avoid requiring Python at runtime (e.g. the python execution is commented out in bufr_dump_decode_python.sh). Consider generating the repeated values using pure shell/awk to keep the test environment requirements minimal.

Suggested change
set values = {$(python3 -c "print(','.join(['273.15']*100))")};
set values = {$(awk 'BEGIN{for(i=1;i<=100;i++){printf "%s", "273.15"; if(i<100) printf ","}}')};

Copilot uses AI. Check for mistakes.
write;
EOF
tempConst=temp.${label}.const.grib
${tools_dir}/grib_filter -o $tempConst $tempFilt $ECCODES_SAMPLES_PATH/GRIB2.tmpl 2>/dev/null || true
if [ -f "$tempConst" ]; then
max=$(${tools_dir}/grib_get -p max $tempConst)
min=$(${tools_dir}/grib_get -p min $tempConst)
echo "Constant field: max=$max min=$min"
fi

rm -f $tempGrib $tempOut $tempRef $tempFilt $tempConst
Loading
Loading