Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ebdf75b
tests for aux_progs
AlysonStahl-NOAA Dec 3, 2025
df3e3eb
Merge branch 'develop' into as_aux
AlysonStahl-NOAA Dec 3, 2025
4c54757
function declarations
AlysonStahl-NOAA Dec 3, 2025
819694b
Merge branch 'as_aux' of https://github.com/AlysonStahl-NOAA/wgrib2 i…
AlysonStahl-NOAA Dec 3, 2025
3cb3fed
Update CMakeLists.txt
AlysonStahl-NOAA Dec 3, 2025
cb94581
silence unused variable warning
AlysonStahl-NOAA Dec 3, 2025
6de40f1
move rd_msg() to new file
AlysonStahl-NOAA Dec 3, 2025
d2cc8f0
Update test_uint8_32bit.c
AlysonStahl-NOAA Dec 3, 2025
901f8b4
debug msb test
AlysonStahl-NOAA Dec 3, 2025
c46b254
Update test_uint8_64bit.c
AlysonStahl-NOAA Dec 3, 2025
291ee26
debugging uint8
AlysonStahl-NOAA Dec 3, 2025
4b526f9
wrong data type in declaration
AlysonStahl-NOAA Dec 3, 2025
598fe3c
Update test_rd_msg.c
AlysonStahl-NOAA Dec 3, 2025
ca56802
check if new tests are breaking spack
AlysonStahl-NOAA Dec 3, 2025
e4a1cc5
Update CMakeLists.txt
AlysonStahl-NOAA Dec 3, 2025
e66031f
debug spack failure
AlysonStahl-NOAA Dec 3, 2025
1b9763a
Update test_rd_msg.c
AlysonStahl-NOAA Dec 3, 2025
8e1176d
trying to run spack tests verbosely
AlysonStahl-NOAA Dec 3, 2025
c499fd8
debug
AlysonStahl-NOAA Dec 3, 2025
aa283eb
Update test_rd_msg.c
AlysonStahl-NOAA Dec 3, 2025
81f19b0
debug
AlysonStahl-NOAA Dec 3, 2025
de75112
Update test_rd_msg.c
AlysonStahl-NOAA Dec 3, 2025
7e1058f
Update test_rd_msg.c
AlysonStahl-NOAA Dec 3, 2025
6d14a79
Update test_rd_msg.c
AlysonStahl-NOAA Dec 3, 2025
2a7bd74
remove debug code
AlysonStahl-NOAA Dec 3, 2025
da0cab3
Merge branch 'develop' into as_aux
AlysonStahl-NOAA Dec 3, 2025
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
2 changes: 1 addition & 1 deletion aux_progs/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

add_executable(gmerge gmerge.c uint8.c)
add_executable(gmerge gmerge.c rd_msg.c uint8.c)

add_executable(smallest_grib2 smallest_grib2.c uint8.c)

Expand Down
44 changes: 1 addition & 43 deletions aux_progs/gmerge.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* 12/2022 | W. Ebisuzaki | better error messages, list of input files can be 1 file
* 01/2023 | W. Ebisuzaki | updated for 2023, cmake compile added
* 05/2025 | W. Ebisuzaki | increase N again (32..200..system limit)
* 12/2025 | A. Stahl | Moved rd_msg() to rd_msg.c to support testing
*
* @author Public Domain: Wesley Ebisuzaki @date 05/2009
*/
Expand All @@ -24,7 +25,6 @@
/** Current Version of gmerge */
#define VERSION "gmerge v1.6 5/2025"

unsigned long int uint8(unsigned char *);
int rd_msg(FILE *, FILE *);

/**
Expand Down Expand Up @@ -108,45 +108,3 @@ int main(int argc, char **argv) {
exit(0);
}

/** Maximum Buffer Size */
#define BSIZE 4096*8

/**
* Reads a GRIB2 message from the input file and writes it to the output file.
*
* @param in Pointer to the input file.
* @param out Pointer to the output file.
*
* @return 0 on success, non-zero on error.
*
* @author Wesley Ebisuzaki @date 05/2009
*/
int rd_msg(FILE *in, FILE *out) {
long unsigned int n;
int i,j,k;
unsigned char header[BSIZE];

if (feof(in)) return -1;

i = fread(header, 1, 16, in);
if (i != 16) return -1;
if (header[0] != 'G' || header[1] != 'R' || header[2] != 'I' ||
header[3] != 'B') return -1;

n = uint8(&(header[8]));

j = n < BSIZE ? n : BSIZE;
k = fread(header+16,1,j-16,in);
if (k != j-16) return -1;

fwrite(header,1,j,out);
n -= j;

while (n) {
j = n < BSIZE ? n : BSIZE;
k = fread(header,1,j,in);
fwrite(header,1,j,out);
n -= j;
}
return 0;
}
59 changes: 59 additions & 0 deletions aux_progs/rd_msg.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/** @file
* @brief Reads a GRIB2 message from input file and writes it to output file. Supports gmerge.c.
*
* ### Program History Log
* Date | Programmer | Comments
* -----|------------|---------
* 05/2009 | W. Ebisuzaki | Initial
* 12/2025 | A. Stahl | Moved from gmerge.c to support testing
* @author Public Domain: Wesley Ebisuzaki @date 05/2009
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

unsigned long int uint8(unsigned char *);

/** Maximum Buffer Size */
#define BSIZE 4096*8

/**
* Reads a GRIB2 message from the input file and writes it to the output file.
*
* @param in Pointer to the input file.
* @param out Pointer to the output file.
*
* @return 0 on success, non-zero on error.
*
* @author Wesley Ebisuzaki @date 05/2009
*/
int rd_msg(FILE *in, FILE *out) {
long unsigned int n;
int i,j,k;
unsigned char header[BSIZE];

if (feof(in)) return -1;

i = fread(header, 1, 16, in);
if (i != 16) return -1;
if (header[0] != 'G' || header[1] != 'R' || header[2] != 'I' ||
header[3] != 'B') return -1;

n = uint8(&(header[8]));

j = n < BSIZE ? n : BSIZE;
k = fread(header+16,1,j-16,in);
if (k != j-16) return -1;

fwrite(header,1,j,out);
n -= j;

while (n) {
j = n < BSIZE ? n : BSIZE;
k = fread(header,1,j,in);
fwrite(header,1,j,out);
n -= j;
}
return 0;
}
18 changes: 18 additions & 0 deletions aux_progs/uint8.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@
#include <limits.h>
#include "grb2.h"

/** For unit tests only. Sets ULONG_MAX to 32-bit max if FORCE_32BIT_TEST is defined. */
#ifdef FORCE_32BIT_TEST
#undef ULONG_MAX
#define ULONG_MAX 4294967295UL
#endif

/**
* Converts an 8-byte unsigned integer from a byte array to an unsigned long integer.
*
* @param p Pointer to an array of at least 8 bytes representing the unsigned integer in big-endian order.
*
* @return The converted unsigned long integer.
*
* @note On 32-bit systems, if the value exceeds the maximum representable value of unsigned long int,
* the program will print an error message and exit.
*
* @author Wesley Ebisuzaki @date 2006
*/
unsigned long int uint8(unsigned char *p) {

#if (ULONG_MAX == 4294967295UL)
Expand Down
23 changes: 23 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,29 @@ copy_test_data(ref_jpeg2simple.txt)
copy_test_data(LARGECAT220250305_12_1443copy.grib2)
copy_test_data(ref_LARGECAT220250305_12_1443copy_stats.txt)

# Build and run tests for auxillary programs.

if(CMAKE_SIZEOF_VOID_P EQUAL 8)
# Test normal 64-bit behavior
add_executable(test_uint8_64bit test_uint8_64bit.c ${CMAKE_SOURCE_DIR}/aux_progs/uint8.c)
target_include_directories(test_uint8_64bit PRIVATE ${CMAKE_SOURCE_DIR}/aux_progs)
add_test(NAME test_uint8_64bit COMMAND test_uint8_64bit)

# Test 32-bit behavior on 64-bit system using FORCE_32BIT_TEST
add_executable(test_uint8_32bit test_uint8_32bit.c ${CMAKE_SOURCE_DIR}/aux_progs/uint8.c)
target_include_directories(test_uint8_32bit PRIVATE ${CMAKE_SOURCE_DIR}/aux_progs)
target_compile_definitions(test_uint8_32bit PRIVATE FORCE_32BIT_TEST)
add_test(NAME test_uint8_32bit COMMAND test_uint8_32bit)
else()
add_executable(test_uint8_32bit test_uint8_32bit.c ${CMAKE_SOURCE_DIR}/aux_progs/uint8.c)
target_include_directories(test_uint8_32bit PRIVATE ${CMAKE_SOURCE_DIR}/aux_progs)
add_test(NAME test_uint8_32bit COMMAND test_uint8_32bit)
endif()

add_executable(test_rd_msg test_rd_msg.c ${CMAKE_SOURCE_DIR}/aux_progs/rd_msg.c
${CMAKE_SOURCE_DIR}/aux_progs/uint8.c)
target_include_directories(test_rd_msg PRIVATE ${CMAKE_SOURCE_DIR}/aux_progs)
add_test(NAME test_rd_msg COMMAND test_rd_msg)

if (MAKE_FTN_API)
build_ftn_api_test(test_fortran_api)
Expand Down
164 changes: 164 additions & 0 deletions tests/test_rd_msg.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/**
* This is a test for the gmerge helper function rd_msg().
*
* Alyson Stahl
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int rd_msg(FILE *in, FILE *out);

int
main()
{
printf("Testing gmerge helper function rd_msg()...\n");
printf("EOF on first read. Should return -1.");
{
FILE *input, *output;
int result;

// Create empty file
input = fopen("test_empty.tmp", "wb");
fclose(input);

input = fopen("test_empty.tmp", "rb");
output = fopen("test_output.tmp", "wb");
result = rd_msg(input, output);

fclose(input);
fclose(output);

remove("test_empty.tmp");
remove("test_output.tmp");

if (result != -1) return 1;
}
printf("ok!\n");
printf("Invalid GRIB header. Should return -1.");
{
FILE *input, *output;
unsigned char bad_data[16];
int result;

memset(bad_data, 0, 16);
strcpy((char*)bad_data, "BADHEADER");

input = fopen("test_bad.tmp", "wb");
fwrite(bad_data, 1, 16, input);
fclose(input);

input = fopen("test_bad.tmp", "rb");
output = fopen("test_output.tmp", "wb");

result = rd_msg(input, output);

fclose(input);
fclose(output);
remove("test_bad.tmp");
remove("test_output.tmp");

if (result != -1) return 2;
}
printf("ok!\n");
printf("Message too large (> 1GB). Should return -1.");
{
FILE *input, *output;
unsigned char large_header[16];
int result;

memset(large_header, 0, 16);
strcpy((char*)large_header, "GRIB");
// Set message length to > 1GB
large_header[8] = 0x00;
large_header[9] = 0x00;
large_header[10] = 0x00;
large_header[11] = 0x40; // 1GB = 0x40000000
large_header[12] = 0x00;
large_header[13] = 0x00;
large_header[14] = 0x00;
large_header[15] = 0x00;

input = fopen("test_large.tmp", "wb");
fwrite(large_header, 1, 16, input);
fclose(input);

input = fopen("test_large.tmp", "rb");
output = fopen("test_output.tmp", "wb");

result = rd_msg(input, output);

fclose(input);
fclose(output);
remove("test_large.tmp");
remove("test_output.tmp");

if (result != -1) return 3;
}
printf("ok!\n");
printf("Incomplete message read. Should return -1.");
{
FILE *input, *output;
unsigned char incomplete_header[16];
int result;

memset(incomplete_header, 0, 16);
strcpy((char*)incomplete_header, "GRIB");
// Set message length to 32 bytes
incomplete_header[15] = 32;

input = fopen("test_incomplete.tmp", "wb");
fwrite(incomplete_header, 1, 16, input);
// Write only 8 more bytes instead of 16
unsigned char partial_data[8] = {0};
fwrite(partial_data, 1, 8, input);
fclose(input);

input = fopen("test_incomplete.tmp", "rb");
output = fopen("test_output.tmp", "wb");

result = rd_msg(input, output);

fclose(input);
fclose(output);
remove("test_incomplete.tmp");
remove("test_output.tmp");

if (result != -1) return 4;
}
printf("ok!\n");
printf("Valid GRIB message. Should return 0.");
{
FILE *input, *output;
unsigned char valid_header[16];
int result;

memset(valid_header, 0, 16);
strcpy((char*)valid_header, "GRIB");
// Set message length to 32 bytes
valid_header[15] = 32;

input = fopen("test_valid.tmp", "wb");
fwrite(valid_header, 1, 16, input);
// Write 16 more bytes of data
unsigned char data[16] = {0};
fwrite(data, 1, 16, input);
fclose(input);

input = fopen("test_valid.tmp", "rb");
output = fopen("test_output.tmp", "wb");

result = rd_msg(input, output);

fclose(input);
fclose(output);
remove("test_valid.tmp");
remove("test_output.tmp");

if (result != 0) return 5;
}
printf("ok!\n");
printf("SUCCESS!\n");
return 0;
}
Loading
Loading