From 22ea48ca965b81242ffa67830cd90e36df048472 Mon Sep 17 00:00:00 2001 From: Nishant Bansal Date: Sun, 5 Jan 2025 12:34:35 +0530 Subject: [PATCH 1/7] r.describe: add JSON output Signed-off-by: Nishant Bansal --- raster/r.describe/Makefile | 2 +- raster/r.describe/describe.c | 12 +- raster/r.describe/dumplist.c | 351 +++++++++++++++++++++++++++----- raster/r.describe/local_proto.h | 18 +- raster/r.describe/main.c | 17 +- 5 files changed, 333 insertions(+), 67 deletions(-) diff --git a/raster/r.describe/Makefile b/raster/r.describe/Makefile index ddd265e6d58..52ba3114f4d 100644 --- a/raster/r.describe/Makefile +++ b/raster/r.describe/Makefile @@ -2,7 +2,7 @@ MODULE_TOPDIR = ../.. PGM = r.describe -LIBES = $(RASTERLIB) $(GISLIB) +LIBES = $(RASTERLIB) $(GISLIB) $(PARSONLIB) DEPENDENCIES = $(RASTERDEP) $(GISDEP) include $(MODULE_TOPDIR)/include/Make/Module.make diff --git a/raster/r.describe/describe.c b/raster/r.describe/describe.c index 69b65aeec6e..11540d93267 100644 --- a/raster/r.describe/describe.c +++ b/raster/r.describe/describe.c @@ -18,10 +18,12 @@ #include #include #include + #include "local_proto.h" int describe(const char *name, int compact, char *no_data_str, int range, - int windowed, int nsteps, int as_int, int skip_nulls) + int windowed, int nsteps, int as_int, int skip_nulls, + enum OutputFormat format) { int fd; struct Cell_stats statf; @@ -127,20 +129,20 @@ int describe(const char *name, int compact, char *no_data_str, int range, if (range) { if (compact) compact_range_list(negmin, negmax, zero, posmin, posmax, null, - no_data_str, skip_nulls); + no_data_str, skip_nulls, format); else range_list(negmin, negmax, zero, posmin, posmax, null, no_data_str, - skip_nulls); + skip_nulls, format); } else { Rast_rewind_cell_stats(&statf); if (compact) compact_list(&statf, dmin, dmax, no_data_str, skip_nulls, map_type, - nsteps); + nsteps, format); else long_list(&statf, dmin, dmax, no_data_str, skip_nulls, map_type, - nsteps); + nsteps, format); Rast_free_cell_stats(&statf); } diff --git a/raster/r.describe/dumplist.c b/raster/r.describe/dumplist.c index 7191679463b..de355e80ad3 100644 --- a/raster/r.describe/dumplist.c +++ b/raster/r.describe/dumplist.c @@ -18,43 +18,136 @@ #include #include #include +#include -static int show(CELL, CELL, int *, DCELL, DCELL, RASTER_MAP_TYPE, int); +#include "local_proto.h" + +static int show(CELL, CELL, int *, DCELL, DCELL, RASTER_MAP_TYPE, int, + enum OutputFormat, JSON_Array *); +static void initialize_json_array(JSON_Value **, JSON_Array **); +static void json_append_category_value(JSON_Array *, const char *); +static void output_pretty_json(JSON_Value *); + +void initialize_json_array(JSON_Value **root_value, JSON_Array **root_array) +{ + *root_value = json_value_init_array(); + if (*root_value == NULL) { + G_fatal_error(_("Failed to initialize JSON array. Out of memory?")); + } + *root_array = json_array(*root_value); +} + +void json_append_category_value(JSON_Array *root_array, const char *cat_str) +{ + JSON_Value *category_value; + JSON_Object *category; + + category_value = json_value_init_object(); + if (category_value == NULL) { + G_fatal_error(_("Failed to initialize JSON array. Out of memory?")); + } + category = json_object(category_value); + + json_object_set_string(category, "value", cat_str); + json_array_append_value(root_array, category_value); +} + +void output_pretty_json(JSON_Value *root_value) +{ + char *serialized_string = json_serialize_to_string_pretty(root_value); + if (!serialized_string) { + json_value_free(root_value); + G_fatal_error(_("Failed to initialize pretty JSON string.")); + } + puts(serialized_string); + + json_free_serialized_string(serialized_string); + json_value_free(root_value); +} int long_list(struct Cell_stats *statf, DCELL dmin, DCELL dmax, char *no_data_str, int skip_nulls, RASTER_MAP_TYPE map_type, - int nsteps) + int nsteps, enum OutputFormat format) { CELL cat; long count; /* not used, but required by cell stats call */ + char cat_str[MAX_STR_LEN]; + JSON_Value *root_value; + JSON_Array *root_array; + + if (format == JSON) { + initialize_json_array(&root_value, &root_array); + } Rast_get_stats_for_null_value(&count, statf); - if (count != 0 && !skip_nulls) - fprintf(stdout, "%s\n", no_data_str); + if (count != 0 && !skip_nulls) { + switch (format) { + case PLAIN: + fprintf(stdout, "%s\n", no_data_str); + break; + case JSON: + json_append_category_value(root_array, no_data_str); + break; + } + } while (Rast_next_cell_stat(&cat, &count, statf)) { - if (map_type != CELL_TYPE) - fprintf(stdout, "%f-%f\n", - dmin + (double)(cat - 1) * (dmax - dmin) / nsteps, - dmin + (double)cat * (dmax - dmin) / nsteps); - else - fprintf(stdout, "%ld\n", (long)cat); + switch (format) { + case PLAIN: + if (map_type != CELL_TYPE) + fprintf(stdout, "%f-%f\n", + dmin + (double)(cat - 1) * (dmax - dmin) / nsteps, + dmin + (double)cat * (dmax - dmin) / nsteps); + else + fprintf(stdout, "%ld\n", (long)cat); + break; + case JSON: + if (map_type != CELL_TYPE) { + snprintf(cat_str, sizeof(cat_str), "%f-%f", + dmin + (double)(cat - 1) * (dmax - dmin) / nsteps, + dmin + (double)cat * (dmax - dmin) / nsteps); + } + else { + snprintf(cat_str, sizeof(cat_str), "%ld", (long)cat); + } + json_append_category_value(root_array, cat_str); + break; + } } + + if (format == JSON) { + output_pretty_json(root_value); + } + return (0); } int compact_list(struct Cell_stats *statf, DCELL dmin, DCELL dmax, char *no_data_str, int skip_nulls, RASTER_MAP_TYPE map_type, - int nsteps) + int nsteps, enum OutputFormat format) { CELL cat1, cat2, temp; int len; long count; /* not used, but required by cell stats call */ + JSON_Value *root_value; + JSON_Array *root_array; + + if (format == JSON) { + initialize_json_array(&root_value, &root_array); + } len = 0; Rast_get_stats_for_null_value(&count, statf); - if (count != 0 && !skip_nulls) - fprintf(stdout, "%s ", no_data_str); + if (count != 0 && !skip_nulls) { + switch (format) { + case PLAIN: + fprintf(stdout, "%s ", no_data_str); + break; + case JSON: + json_append_category_value(root_array, no_data_str); + break; + } + } if (!Rast_next_cell_stat(&cat1, &count, statf)) /* map doesn't contain any non-null data */ @@ -63,94 +156,244 @@ int compact_list(struct Cell_stats *statf, DCELL dmin, DCELL dmax, cat2 = cat1; while (Rast_next_cell_stat(&temp, &count, statf)) { if (temp != cat2 + (CELL)1) { - show(cat1, cat2, &len, dmin, dmax, map_type, nsteps); + show(cat1, cat2, &len, dmin, dmax, map_type, nsteps, format, + root_array); cat1 = temp; } cat2 = temp; } - show(cat1, cat2, &len, dmin, dmax, map_type, nsteps); - fprintf(stdout, "\n"); + show(cat1, cat2, &len, dmin, dmax, map_type, nsteps, format, root_array); + + switch (format) { + case PLAIN: + fprintf(stdout, "\n"); + break; + case JSON: + output_pretty_json(root_value); + break; + } + return (0); } static int show(CELL low, CELL high, int *len, DCELL dmin, DCELL dmax, - RASTER_MAP_TYPE map_type, int nsteps) + RASTER_MAP_TYPE map_type, int nsteps, enum OutputFormat format, + JSON_Array *root_array) { - char text[100]; + char text[MAX_STR_LEN]; char xlen; if (low + 1 == high) { - show(low, low, len, dmin, dmax, map_type, nsteps); - show(high, high, len, dmin, dmax, map_type, nsteps); + show(low, low, len, dmin, dmax, map_type, nsteps, format, root_array); + show(high, high, len, dmin, dmax, map_type, nsteps, format, root_array); return 0; } if (map_type != CELL_TYPE) { - sprintf(text, "%f%s%f ", dmin + (low - 1) * (dmax - dmin) / nsteps, - dmin < 0 ? " thru " : "-", - dmin + high * (dmax - dmin) / nsteps); + switch (format) { + case PLAIN: + sprintf(text, "%f%s%f ", dmin + (low - 1) * (dmax - dmin) / nsteps, + dmin < 0 ? " thru " : "-", + dmin + high * (dmax - dmin) / nsteps); + break; + case JSON: + sprintf(text, "%f%s%f", dmin + (low - 1) * (dmax - dmin) / nsteps, + dmin < 0 ? " thru " : "-", + dmin + high * (dmax - dmin) / nsteps); + break; + } } else { - if (low == high) - sprintf(text, "%ld ", (long)low); - else - sprintf(text, "%ld%s%ld ", (long)low, low < 0 ? " thru " : "-", - (long)high); + switch (format) { + case PLAIN: + if (low == high) + sprintf(text, "%ld ", (long)low); + else + sprintf(text, "%ld%s%ld ", (long)low, low < 0 ? " thru " : "-", + (long)high); + break; + case JSON: + if (low == high) + sprintf(text, "%ld", (long)low); + else + sprintf(text, "%ld%s%ld", (long)low, low < 0 ? " thru " : "-", + (long)high); + break; + } } xlen = strlen(text); if (xlen + *len > 78) { - fprintf(stdout, "\n"); + if (format == PLAIN) + fprintf(stdout, "\n"); *len = 0; } - fprintf(stdout, "%s", text); + + switch (format) { + case PLAIN: + fprintf(stdout, "%s", text); + break; + case JSON: + json_append_category_value(root_array, text); + break; + } + *len += xlen; return (0); } int compact_range_list(CELL negmin, CELL negmax, CELL zero, CELL posmin, CELL posmax, CELL null, char *no_data_str, - int skip_nulls) + int skip_nulls, enum OutputFormat format) { + char cat_str[MAX_STR_LEN]; + JSON_Value *root_value; + JSON_Array *root_array; + + if (format == JSON) { + initialize_json_array(&root_value, &root_array); + } + if (negmin) { - fprintf(stdout, "%ld", (long)negmin); - if (negmin != negmax) - fprintf(stdout, " thru %ld", (long)negmax); - fprintf(stdout, "\n"); + switch (format) { + case PLAIN: + fprintf(stdout, "%ld", (long)negmin); + if (negmin != negmax) + fprintf(stdout, " thru %ld", (long)negmax); + fprintf(stdout, "\n"); + break; + case JSON: + snprintf(cat_str, sizeof(cat_str), "%ld", (long)negmin); + if (negmin != negmax) + snprintf(cat_str, sizeof(cat_str), "%ld thru %ld", (long)negmin, + (long)negmax); + + json_append_category_value(root_array, cat_str); + break; + } + } + if (zero) { + switch (format) { + case PLAIN: + fprintf(stdout, "0\n"); + break; + case JSON: + json_append_category_value(root_array, "0"); + break; + } } - if (zero) - fprintf(stdout, "0\n"); if (posmin) { - fprintf(stdout, "%ld", (long)posmin); - if (posmin != posmax) - fprintf(stdout, " thru %ld", (long)posmax); - fprintf(stdout, "\n"); + switch (format) { + case PLAIN: + fprintf(stdout, "%ld", (long)posmin); + if (posmin != posmax) + fprintf(stdout, " thru %ld", (long)posmax); + fprintf(stdout, "\n"); + break; + case JSON: + snprintf(cat_str, sizeof(cat_str), "%ld", (long)posmin); + if (posmin != posmax) + snprintf(cat_str, sizeof(cat_str), "%ld thru %ld", (long)posmin, + (long)posmax); + + json_append_category_value(root_array, cat_str); + break; + } + } + + if (null && !skip_nulls) { + switch (format) { + case PLAIN: + fprintf(stdout, "%s\n", no_data_str); + break; + case JSON: + json_append_category_value(root_array, no_data_str); + break; + } } - if (null && !skip_nulls) - fprintf(stdout, "%s\n", no_data_str); + if (format == JSON) { + output_pretty_json(root_value); + } return (0); } int range_list(CELL negmin, CELL negmax, CELL zero, CELL posmin, CELL posmax, - CELL null, char *no_data_str, int skip_nulls) + CELL null, char *no_data_str, int skip_nulls, + enum OutputFormat format) { + char cat_str[MAX_STR_LEN]; + JSON_Value *root_value; + JSON_Array *root_array; + + if (format == JSON) { + initialize_json_array(&root_value, &root_array); + } + if (negmin) { - fprintf(stdout, "%ld\n", (long)negmin); - if (negmin != negmax) - fprintf(stdout, "%ld\n", (long)negmax); + switch (format) { + case PLAIN: + fprintf(stdout, "%ld\n", (long)negmin); + if (negmin != negmax) + fprintf(stdout, "%ld\n", (long)negmax); + break; + case JSON: + snprintf(cat_str, sizeof(cat_str), "%ld", (long)negmin); + json_append_category_value(root_array, cat_str); + + if (negmin != negmax) { + snprintf(cat_str, sizeof(cat_str), "%ld", (long)negmax); + json_append_category_value(root_array, cat_str); + } + break; + } } - if (zero) - fprintf(stdout, "0\n"); + + if (zero) { + switch (format) { + case PLAIN: + fprintf(stdout, "0\n"); + break; + case JSON: + json_append_category_value(root_array, "0"); + break; + } + } + if (posmin) { - fprintf(stdout, "%ld\n", (long)posmin); - if (posmin != posmax) - fprintf(stdout, "%ld\n", (long)posmax); + switch (format) { + case PLAIN: + fprintf(stdout, "%ld\n", (long)posmin); + if (posmin != posmax) + fprintf(stdout, "%ld\n", (long)posmax); + break; + case JSON: + snprintf(cat_str, sizeof(cat_str), "%ld", (long)posmin); + json_append_category_value(root_array, cat_str); + + if (posmin != posmax) { + snprintf(cat_str, sizeof(cat_str), "%ld", (long)posmax); + json_append_category_value(root_array, cat_str); + } + break; + } } - if (null && !skip_nulls) - fprintf(stdout, "%s\n", no_data_str); + if (null && !skip_nulls) { + switch (format) { + case PLAIN: + fprintf(stdout, "%s\n", no_data_str); + break; + case JSON: + json_append_category_value(root_array, no_data_str); + break; + } + } + + if (format == JSON) { + output_pretty_json(root_value); + } return (0); } diff --git a/raster/r.describe/local_proto.h b/raster/r.describe/local_proto.h index 530f7e0565b..0ebbec32bc1 100644 --- a/raster/r.describe/local_proto.h +++ b/raster/r.describe/local_proto.h @@ -19,17 +19,25 @@ #define __R_DESC_LOCAL_PROTO_H__ #include +#include + +#define MAX_STR_LEN 100 + +enum OutputFormat { PLAIN, JSON }; /* describe.c */ -int describe(const char *, int, char *, int, int, int, int, int); +int describe(const char *, int, char *, int, int, int, int, int, + enum OutputFormat); /* dumplist.c */ int long_list(struct Cell_stats *, DCELL, DCELL, char *, int, RASTER_MAP_TYPE, - int); + int, enum OutputFormat); int compact_list(struct Cell_stats *, DCELL, DCELL, char *, int, - RASTER_MAP_TYPE, int); -int compact_range_list(CELL, CELL, CELL, CELL, CELL, CELL, char *, int); -int range_list(CELL, CELL, CELL, CELL, CELL, CELL, char *, int); + RASTER_MAP_TYPE, int, enum OutputFormat); +int compact_range_list(CELL, CELL, CELL, CELL, CELL, CELL, char *, int, + enum OutputFormat); +int range_list(CELL, CELL, CELL, CELL, CELL, CELL, char *, int, + enum OutputFormat); /* main.c */ int main(int, char *[]); diff --git a/raster/r.describe/main.c b/raster/r.describe/main.c index 394a228871b..c4e204ba0cf 100644 --- a/raster/r.describe/main.c +++ b/raster/r.describe/main.c @@ -19,9 +19,10 @@ #include #include #include -#include "local_proto.h" #include +#include "local_proto.h" + int main(int argc, char *argv[]) { int as_int; @@ -42,7 +43,9 @@ int main(int argc, char *argv[]) struct Option *map; struct Option *nv; struct Option *nsteps; + struct Option *format; } option; + enum OutputFormat format; G_gisinit(argv[0]); @@ -66,6 +69,9 @@ int main(int argc, char *argv[]) option.nsteps->answer = "255"; option.nsteps->description = _("Number of quantization steps"); + option.format = G_define_standard_option(G_OPT_F_FORMAT); + option.format->guisection = _("Print"); + /*define the different flags */ flag.one = G_define_flag(); @@ -97,12 +103,19 @@ int main(int argc, char *argv[]) as_int = flag.i->answer; no_data_str = option.nv->answer; + if (strcmp(option.format->answer, "json") == 0) { + format = JSON; + } + else { + format = PLAIN; + } + if (sscanf(option.nsteps->answer, "%d", &nsteps) != 1 || nsteps < 1) G_fatal_error(_("%s = %s -- must be greater than zero"), option.nsteps->key, option.nsteps->answer); describe(option.map->answer, compact, no_data_str, range, windowed, nsteps, - as_int, flag.n->answer); + as_int, flag.n->answer, format); return EXIT_SUCCESS; } From 706fa755fdd24a575acc0c289e682dd8074aaf60 Mon Sep 17 00:00:00 2001 From: Nishant Bansal Date: Sun, 5 Jan 2025 12:35:24 +0530 Subject: [PATCH 2/7] r.describe: add unit test Signed-off-by: Nishant Bansal --- .../r.describe/testsuite/test_r_describe.py | 400 ++++++++++++++++++ 1 file changed, 400 insertions(+) create mode 100644 raster/r.describe/testsuite/test_r_describe.py diff --git a/raster/r.describe/testsuite/test_r_describe.py b/raster/r.describe/testsuite/test_r_describe.py new file mode 100644 index 00000000000..d4da8fb93ea --- /dev/null +++ b/raster/r.describe/testsuite/test_r_describe.py @@ -0,0 +1,400 @@ +import json + +from grass.gunittest.case import TestCase +from grass.gunittest.main import test +from grass.gunittest.gmodules import SimpleModule + + +class TestRDescribe(TestCase): + + @classmethod + def setUpClass(cls): + """Set up a temporary region and generate test data.""" + cls.use_temp_region() + cls.runModule("g.region", n=10, s=0, e=10, w=0, res=1) + + cls.runModule( + "r.mapcalc", + expression="map = if(row() == 5 && col() == 5, null(), if(row() % 2 == 0, col() * 0.5, -col() * 0.5))", + overwrite=True, + ) + + @classmethod + def tearDownClass(cls): + """Clean up after tests.""" + cls.runModule( + "g.remove", flags="f", type="raster", name=["map"] + ) + cls.del_temp_region() + + def test_plain_describe(self): + """Test r.describe with the default output format.""" + module = SimpleModule("r.describe", map="map") + self.assertModule(module) + + result = module.outputs.stdout.strip().splitlines() + + expected_results = [ + "* -5.000000 thru -4.960784 -4.529412 thru -4.490196 -4.019608 thru -3.980392 ", + "-3.509804 thru -3.470588 -3.039216 thru -3.000000 -2.529412 thru -2.490196 ", + "-2.019608 thru -1.980392 -1.549020 thru -1.509804 -1.039216 thru -1.000000 ", + "-0.529412 thru -0.490196 0.450980 thru 0.490196 0.960784 thru 1.000000 ", + "1.470588 thru 1.509804 1.941176 thru 1.980392 2.450980 thru 2.490196 ", + "2.960784 thru 3.000000 3.431373 thru 3.470588 3.941176 thru 3.980392 ", + "4.450980 thru 4.490196 4.960784 thru 5.000000" + ] + + for i, component in enumerate(result): + self.assertEqual( + component, expected_results[i], f"Mismatch at line {i + 1}" + ) + + def test_plain_describe_with_one_flag(self): + """Test r.describe with the plain output format and the -1 flag.""" + module = SimpleModule("r.describe", map="map",flags="1") + self.assertModule(module) + + result = module.outputs.stdout.strip().splitlines() + + expected_results = [ + "*", + "-5.000000--4.960784", + "-4.529412--4.490196", + "-4.019608--3.980392", + "-3.509804--3.470588", + "-3.039216--3.000000", + "-2.529412--2.490196", + "-2.019608--1.980392", + "-1.549020--1.509804", + "-1.039216--1.000000", + "-0.529412--0.490196", + "0.450980-0.490196", + "0.960784-1.000000", + "1.470588-1.509804", + "1.941176-1.980392", + "2.450980-2.490196", + "2.960784-3.000000", + "3.431373-3.470588", + "3.941176-3.980392", + "4.450980-4.490196", + "4.960784-5.000000" + ] + + for i, component in enumerate(result): + self.assertEqual( + component, expected_results[i], f"Mismatch at line {i + 1}" + ) + + def test_plain_describe_with_r_flag(self): + """Test r.describe with the plain output format and the -r flag.""" + module = SimpleModule("r.describe", map="map",flags="r") + self.assertModule(module) + + result = module.outputs.stdout.strip().splitlines() + + expected_results = ["* -5.000000 thru 5.000000"] + + for i, component in enumerate(result): + self.assertEqual( + component, expected_results[i], f"Mismatch at line {i + 1}" + ) + + def test_plain_describe_with_i_flag(self): + """Test r.describe with the plain output format and the -i flag.""" + module = SimpleModule("r.describe", map="map",flags="i") + self.assertModule(module) + + result = module.outputs.stdout.strip().splitlines() + + expected_results = ["* -5 thru -1 1-5"] + + for i, component in enumerate(result): + self.assertEqual( + component, expected_results[i], f"Mismatch at line {i + 1}" + ) + + def test_plain_describe_with_n_flag(self): + """Test r.describe with the plain output format and the -n flag.""" + module = SimpleModule("r.describe", map="map",flags="n") + self.assertModule(module) + + result = module.outputs.stdout.strip().splitlines() + + expected_results = [ + "-5.000000 thru -4.960784 -4.529412 thru -4.490196 -4.019608 thru -3.980392 ", + "-3.509804 thru -3.470588 -3.039216 thru -3.000000 -2.529412 thru -2.490196 ", + "-2.019608 thru -1.980392 -1.549020 thru -1.509804 -1.039216 thru -1.000000 ", + "-0.529412 thru -0.490196 0.450980 thru 0.490196 0.960784 thru 1.000000 ", + "1.470588 thru 1.509804 1.941176 thru 1.980392 2.450980 thru 2.490196 ", + "2.960784 thru 3.000000 3.431373 thru 3.470588 3.941176 thru 3.980392 ", + "4.450980 thru 4.490196 4.960784 thru 5.000000" + ] + + for i, component in enumerate(result): + self.assertEqual( + component, expected_results[i], f"Mismatch at line {i + 1}" + ) + + def test_json_describe(self): + """Test r.describe with the json output format.""" + module = SimpleModule("r.describe", map="map",format="json") + self.assertModule(module) + + result = json.loads(module.outputs.stdout) + + expected_results = [ + { + "value": "*" + }, + { + "value": "-5.000000 thru -4.960784" + }, + { + "value": "-4.529412 thru -4.490196" + }, + { + "value": "-4.019608 thru -3.980392" + }, + { + "value": "-3.509804 thru -3.470588" + }, + { + "value": "-3.039216 thru -3.000000" + }, + { + "value": "-2.529412 thru -2.490196" + }, + { + "value": "-2.019608 thru -1.980392" + }, + { + "value": "-1.549020 thru -1.509804" + }, + { + "value": "-1.039216 thru -1.000000" + }, + { + "value": "-0.529412 thru -0.490196" + }, + { + "value": "0.450980 thru 0.490196" + }, + { + "value": "0.960784 thru 1.000000" + }, + { + "value": "1.470588 thru 1.509804" + }, + { + "value": "1.941176 thru 1.980392" + }, + { + "value": "2.450980 thru 2.490196" + }, + { + "value": "2.960784 thru 3.000000" + }, + { + "value": "3.431373 thru 3.470588" + }, + { + "value": "3.941176 thru 3.980392" + }, + { + "value": "4.450980 thru 4.490196" + }, + { + "value": "4.960784 thru 5.000000" + } + ] + + self.assertListEqual(expected_results, result) + + def test_json_describe_with_one_flag(self): + """Test r.describe with the json output format and the -1 flag.""" + module = SimpleModule("r.describe", map="map",flags="1",format="json") + self.assertModule(module) + + result = json.loads(module.outputs.stdout) + + expected_results = [ + { + "value": "*" + }, + { + "value": "-5.000000--4.960784" + }, + { + "value": "-4.529412--4.490196" + }, + { + "value": "-4.019608--3.980392" + }, + { + "value": "-3.509804--3.470588" + }, + { + "value": "-3.039216--3.000000" + }, + { + "value": "-2.529412--2.490196" + }, + { + "value": "-2.019608--1.980392" + }, + { + "value": "-1.549020--1.509804" + }, + { + "value": "-1.039216--1.000000" + }, + { + "value": "-0.529412--0.490196" + }, + { + "value": "0.450980-0.490196" + }, + { + "value": "0.960784-1.000000" + }, + { + "value": "1.470588-1.509804" + }, + { + "value": "1.941176-1.980392" + }, + { + "value": "2.450980-2.490196" + }, + { + "value": "2.960784-3.000000" + }, + { + "value": "3.431373-3.470588" + }, + { + "value": "3.941176-3.980392" + }, + { + "value": "4.450980-4.490196" + }, + { + "value": "4.960784-5.000000" + } + ] + + self.assertListEqual(expected_results, result) + + def test_json_describe_with_r_flag(self): + """Test r.describe with the json output format and the -r flag.""" + module = SimpleModule("r.describe", map="map",flags="r",format="json") + self.assertModule(module) + + result = json.loads(module.outputs.stdout) + + expected_results = [ + { + "value": "*" + }, + { + "value": "-5.000000 thru 5.000000" + } + ] + + self.assertListEqual(expected_results, result) + + def test_json_describe_with_i_flag(self): + """Test r.describe with the json output format and the -i flag.""" + module = SimpleModule("r.describe", map="map",flags="i",format="json") + self.assertModule(module) + + result = json.loads(module.outputs.stdout) + + expected_results = [ + { + "value": "*" + }, + { + "value": "-5 thru -1" + }, + { + "value": "1-5" + } + ] + + self.assertListEqual(expected_results, result) + + def test_json_describe_with_n_flag(self): + """Test r.describe with the json output format and the -n flag.""" + module = SimpleModule("r.describe", map="map",flags="n",format="json") + self.assertModule(module) + + result = json.loads(module.outputs.stdout) + + expected_results = [ + { + "value": "-5.000000 thru -4.960784" + }, + { + "value": "-4.529412 thru -4.490196" + }, + { + "value": "-4.019608 thru -3.980392" + }, + { + "value": "-3.509804 thru -3.470588" + }, + { + "value": "-3.039216 thru -3.000000" + }, + { + "value": "-2.529412 thru -2.490196" + }, + { + "value": "-2.019608 thru -1.980392" + }, + { + "value": "-1.549020 thru -1.509804" + }, + { + "value": "-1.039216 thru -1.000000" + }, + { + "value": "-0.529412 thru -0.490196" + }, + { + "value": "0.450980 thru 0.490196" + }, + { + "value": "0.960784 thru 1.000000" + }, + { + "value": "1.470588 thru 1.509804" + }, + { + "value": "1.941176 thru 1.980392" + }, + { + "value": "2.450980 thru 2.490196" + }, + { + "value": "2.960784 thru 3.000000" + }, + { + "value": "3.431373 thru 3.470588" + }, + { + "value": "3.941176 thru 3.980392" + }, + { + "value": "4.450980 thru 4.490196" + }, + { + "value": "4.960784 thru 5.000000" + } + ] + + self.assertListEqual(expected_results, result) + +if __name__ == "__main__": + test() From 28623deedd1b04e84103a9523bf786814a8f7a07 Mon Sep 17 00:00:00 2001 From: Nishant Bansal Date: Sun, 5 Jan 2025 12:47:10 +0530 Subject: [PATCH 3/7] fixes pre-commit issues Signed-off-by: Nishant Bansal --- .../r.describe/testsuite/test_r_describe.py | 336 +++++------------- 1 file changed, 97 insertions(+), 239 deletions(-) diff --git a/raster/r.describe/testsuite/test_r_describe.py b/raster/r.describe/testsuite/test_r_describe.py index d4da8fb93ea..f1fbdf97daf 100644 --- a/raster/r.describe/testsuite/test_r_describe.py +++ b/raster/r.describe/testsuite/test_r_describe.py @@ -22,9 +22,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): """Clean up after tests.""" - cls.runModule( - "g.remove", flags="f", type="raster", name=["map"] - ) + cls.runModule("g.remove", flags="f", type="raster", name=["map"]) cls.del_temp_region() def test_plain_describe(self): @@ -35,23 +33,23 @@ def test_plain_describe(self): result = module.outputs.stdout.strip().splitlines() expected_results = [ - "* -5.000000 thru -4.960784 -4.529412 thru -4.490196 -4.019608 thru -3.980392 ", - "-3.509804 thru -3.470588 -3.039216 thru -3.000000 -2.529412 thru -2.490196 ", - "-2.019608 thru -1.980392 -1.549020 thru -1.509804 -1.039216 thru -1.000000 ", + "* -5.000000 thru -4.960784 -4.529412 thru -4.490196 -4.019608 thru -3.980392 ", + "-3.509804 thru -3.470588 -3.039216 thru -3.000000 -2.529412 thru -2.490196 ", + "-2.019608 thru -1.980392 -1.549020 thru -1.509804 -1.039216 thru -1.000000 ", "-0.529412 thru -0.490196 0.450980 thru 0.490196 0.960784 thru 1.000000 ", - "1.470588 thru 1.509804 1.941176 thru 1.980392 2.450980 thru 2.490196 ", - "2.960784 thru 3.000000 3.431373 thru 3.470588 3.941176 thru 3.980392 ", - "4.450980 thru 4.490196 4.960784 thru 5.000000" + "1.470588 thru 1.509804 1.941176 thru 1.980392 2.450980 thru 2.490196 ", + "2.960784 thru 3.000000 3.431373 thru 3.470588 3.941176 thru 3.980392 ", + "4.450980 thru 4.490196 4.960784 thru 5.000000", ] for i, component in enumerate(result): self.assertEqual( component, expected_results[i], f"Mismatch at line {i + 1}" ) - + def test_plain_describe_with_one_flag(self): """Test r.describe with the plain output format and the -1 flag.""" - module = SimpleModule("r.describe", map="map",flags="1") + module = SimpleModule("r.describe", map="map", flags="1") self.assertModule(module) result = module.outputs.stdout.strip().splitlines() @@ -77,17 +75,17 @@ def test_plain_describe_with_one_flag(self): "3.431373-3.470588", "3.941176-3.980392", "4.450980-4.490196", - "4.960784-5.000000" + "4.960784-5.000000", ] for i, component in enumerate(result): self.assertEqual( component, expected_results[i], f"Mismatch at line {i + 1}" ) - + def test_plain_describe_with_r_flag(self): """Test r.describe with the plain output format and the -r flag.""" - module = SimpleModule("r.describe", map="map",flags="r") + module = SimpleModule("r.describe", map="map", flags="r") self.assertModule(module) result = module.outputs.stdout.strip().splitlines() @@ -98,10 +96,10 @@ def test_plain_describe_with_r_flag(self): self.assertEqual( component, expected_results[i], f"Mismatch at line {i + 1}" ) - + def test_plain_describe_with_i_flag(self): """Test r.describe with the plain output format and the -i flag.""" - module = SimpleModule("r.describe", map="map",flags="i") + module = SimpleModule("r.describe", map="map", flags="i") self.assertModule(module) result = module.outputs.stdout.strip().splitlines() @@ -112,289 +110,149 @@ def test_plain_describe_with_i_flag(self): self.assertEqual( component, expected_results[i], f"Mismatch at line {i + 1}" ) - + def test_plain_describe_with_n_flag(self): """Test r.describe with the plain output format and the -n flag.""" - module = SimpleModule("r.describe", map="map",flags="n") + module = SimpleModule("r.describe", map="map", flags="n") self.assertModule(module) result = module.outputs.stdout.strip().splitlines() expected_results = [ - "-5.000000 thru -4.960784 -4.529412 thru -4.490196 -4.019608 thru -3.980392 ", - "-3.509804 thru -3.470588 -3.039216 thru -3.000000 -2.529412 thru -2.490196 ", - "-2.019608 thru -1.980392 -1.549020 thru -1.509804 -1.039216 thru -1.000000 ", + "-5.000000 thru -4.960784 -4.529412 thru -4.490196 -4.019608 thru -3.980392 ", + "-3.509804 thru -3.470588 -3.039216 thru -3.000000 -2.529412 thru -2.490196 ", + "-2.019608 thru -1.980392 -1.549020 thru -1.509804 -1.039216 thru -1.000000 ", "-0.529412 thru -0.490196 0.450980 thru 0.490196 0.960784 thru 1.000000 ", - "1.470588 thru 1.509804 1.941176 thru 1.980392 2.450980 thru 2.490196 ", - "2.960784 thru 3.000000 3.431373 thru 3.470588 3.941176 thru 3.980392 ", - "4.450980 thru 4.490196 4.960784 thru 5.000000" + "1.470588 thru 1.509804 1.941176 thru 1.980392 2.450980 thru 2.490196 ", + "2.960784 thru 3.000000 3.431373 thru 3.470588 3.941176 thru 3.980392 ", + "4.450980 thru 4.490196 4.960784 thru 5.000000", ] for i, component in enumerate(result): self.assertEqual( component, expected_results[i], f"Mismatch at line {i + 1}" ) - + def test_json_describe(self): """Test r.describe with the json output format.""" - module = SimpleModule("r.describe", map="map",format="json") + module = SimpleModule("r.describe", map="map", format="json") self.assertModule(module) result = json.loads(module.outputs.stdout) expected_results = [ - { - "value": "*" - }, - { - "value": "-5.000000 thru -4.960784" - }, - { - "value": "-4.529412 thru -4.490196" - }, - { - "value": "-4.019608 thru -3.980392" - }, - { - "value": "-3.509804 thru -3.470588" - }, - { - "value": "-3.039216 thru -3.000000" - }, - { - "value": "-2.529412 thru -2.490196" - }, - { - "value": "-2.019608 thru -1.980392" - }, - { - "value": "-1.549020 thru -1.509804" - }, - { - "value": "-1.039216 thru -1.000000" - }, - { - "value": "-0.529412 thru -0.490196" - }, - { - "value": "0.450980 thru 0.490196" - }, - { - "value": "0.960784 thru 1.000000" - }, - { - "value": "1.470588 thru 1.509804" - }, - { - "value": "1.941176 thru 1.980392" - }, - { - "value": "2.450980 thru 2.490196" - }, - { - "value": "2.960784 thru 3.000000" - }, - { - "value": "3.431373 thru 3.470588" - }, - { - "value": "3.941176 thru 3.980392" - }, - { - "value": "4.450980 thru 4.490196" - }, - { - "value": "4.960784 thru 5.000000" - } + {"value": "*"}, + {"value": "-5.000000 thru -4.960784"}, + {"value": "-4.529412 thru -4.490196"}, + {"value": "-4.019608 thru -3.980392"}, + {"value": "-3.509804 thru -3.470588"}, + {"value": "-3.039216 thru -3.000000"}, + {"value": "-2.529412 thru -2.490196"}, + {"value": "-2.019608 thru -1.980392"}, + {"value": "-1.549020 thru -1.509804"}, + {"value": "-1.039216 thru -1.000000"}, + {"value": "-0.529412 thru -0.490196"}, + {"value": "0.450980 thru 0.490196"}, + {"value": "0.960784 thru 1.000000"}, + {"value": "1.470588 thru 1.509804"}, + {"value": "1.941176 thru 1.980392"}, + {"value": "2.450980 thru 2.490196"}, + {"value": "2.960784 thru 3.000000"}, + {"value": "3.431373 thru 3.470588"}, + {"value": "3.941176 thru 3.980392"}, + {"value": "4.450980 thru 4.490196"}, + {"value": "4.960784 thru 5.000000"}, ] self.assertListEqual(expected_results, result) - + def test_json_describe_with_one_flag(self): """Test r.describe with the json output format and the -1 flag.""" - module = SimpleModule("r.describe", map="map",flags="1",format="json") + module = SimpleModule("r.describe", map="map", flags="1", format="json") self.assertModule(module) result = json.loads(module.outputs.stdout) expected_results = [ - { - "value": "*" - }, - { - "value": "-5.000000--4.960784" - }, - { - "value": "-4.529412--4.490196" - }, - { - "value": "-4.019608--3.980392" - }, - { - "value": "-3.509804--3.470588" - }, - { - "value": "-3.039216--3.000000" - }, - { - "value": "-2.529412--2.490196" - }, - { - "value": "-2.019608--1.980392" - }, - { - "value": "-1.549020--1.509804" - }, - { - "value": "-1.039216--1.000000" - }, - { - "value": "-0.529412--0.490196" - }, - { - "value": "0.450980-0.490196" - }, - { - "value": "0.960784-1.000000" - }, - { - "value": "1.470588-1.509804" - }, - { - "value": "1.941176-1.980392" - }, - { - "value": "2.450980-2.490196" - }, - { - "value": "2.960784-3.000000" - }, - { - "value": "3.431373-3.470588" - }, - { - "value": "3.941176-3.980392" - }, - { - "value": "4.450980-4.490196" - }, - { - "value": "4.960784-5.000000" - } + {"value": "*"}, + {"value": "-5.000000--4.960784"}, + {"value": "-4.529412--4.490196"}, + {"value": "-4.019608--3.980392"}, + {"value": "-3.509804--3.470588"}, + {"value": "-3.039216--3.000000"}, + {"value": "-2.529412--2.490196"}, + {"value": "-2.019608--1.980392"}, + {"value": "-1.549020--1.509804"}, + {"value": "-1.039216--1.000000"}, + {"value": "-0.529412--0.490196"}, + {"value": "0.450980-0.490196"}, + {"value": "0.960784-1.000000"}, + {"value": "1.470588-1.509804"}, + {"value": "1.941176-1.980392"}, + {"value": "2.450980-2.490196"}, + {"value": "2.960784-3.000000"}, + {"value": "3.431373-3.470588"}, + {"value": "3.941176-3.980392"}, + {"value": "4.450980-4.490196"}, + {"value": "4.960784-5.000000"}, ] self.assertListEqual(expected_results, result) - + def test_json_describe_with_r_flag(self): """Test r.describe with the json output format and the -r flag.""" - module = SimpleModule("r.describe", map="map",flags="r",format="json") + module = SimpleModule("r.describe", map="map", flags="r", format="json") self.assertModule(module) result = json.loads(module.outputs.stdout) - expected_results = [ - { - "value": "*" - }, - { - "value": "-5.000000 thru 5.000000" - } - ] + expected_results = [{"value": "*"}, {"value": "-5.000000 thru 5.000000"}] self.assertListEqual(expected_results, result) - + def test_json_describe_with_i_flag(self): """Test r.describe with the json output format and the -i flag.""" - module = SimpleModule("r.describe", map="map",flags="i",format="json") + module = SimpleModule("r.describe", map="map", flags="i", format="json") self.assertModule(module) result = json.loads(module.outputs.stdout) - expected_results = [ - { - "value": "*" - }, - { - "value": "-5 thru -1" - }, - { - "value": "1-5" - } - ] + expected_results = [{"value": "*"}, {"value": "-5 thru -1"}, {"value": "1-5"}] self.assertListEqual(expected_results, result) - + def test_json_describe_with_n_flag(self): """Test r.describe with the json output format and the -n flag.""" - module = SimpleModule("r.describe", map="map",flags="n",format="json") + module = SimpleModule("r.describe", map="map", flags="n", format="json") self.assertModule(module) result = json.loads(module.outputs.stdout) expected_results = [ - { - "value": "-5.000000 thru -4.960784" - }, - { - "value": "-4.529412 thru -4.490196" - }, - { - "value": "-4.019608 thru -3.980392" - }, - { - "value": "-3.509804 thru -3.470588" - }, - { - "value": "-3.039216 thru -3.000000" - }, - { - "value": "-2.529412 thru -2.490196" - }, - { - "value": "-2.019608 thru -1.980392" - }, - { - "value": "-1.549020 thru -1.509804" - }, - { - "value": "-1.039216 thru -1.000000" - }, - { - "value": "-0.529412 thru -0.490196" - }, - { - "value": "0.450980 thru 0.490196" - }, - { - "value": "0.960784 thru 1.000000" - }, - { - "value": "1.470588 thru 1.509804" - }, - { - "value": "1.941176 thru 1.980392" - }, - { - "value": "2.450980 thru 2.490196" - }, - { - "value": "2.960784 thru 3.000000" - }, - { - "value": "3.431373 thru 3.470588" - }, - { - "value": "3.941176 thru 3.980392" - }, - { - "value": "4.450980 thru 4.490196" - }, - { - "value": "4.960784 thru 5.000000" - } + {"value": "-5.000000 thru -4.960784"}, + {"value": "-4.529412 thru -4.490196"}, + {"value": "-4.019608 thru -3.980392"}, + {"value": "-3.509804 thru -3.470588"}, + {"value": "-3.039216 thru -3.000000"}, + {"value": "-2.529412 thru -2.490196"}, + {"value": "-2.019608 thru -1.980392"}, + {"value": "-1.549020 thru -1.509804"}, + {"value": "-1.039216 thru -1.000000"}, + {"value": "-0.529412 thru -0.490196"}, + {"value": "0.450980 thru 0.490196"}, + {"value": "0.960784 thru 1.000000"}, + {"value": "1.470588 thru 1.509804"}, + {"value": "1.941176 thru 1.980392"}, + {"value": "2.450980 thru 2.490196"}, + {"value": "2.960784 thru 3.000000"}, + {"value": "3.431373 thru 3.470588"}, + {"value": "3.941176 thru 3.980392"}, + {"value": "4.450980 thru 4.490196"}, + {"value": "4.960784 thru 5.000000"}, ] self.assertListEqual(expected_results, result) + if __name__ == "__main__": test() From 4556a7ed27fc03331c9c745074c3078a0b56f2c4 Mon Sep 17 00:00:00 2001 From: Nishant Bansal Date: Thu, 16 Jan 2025 15:51:15 +0530 Subject: [PATCH 4/7] update r.describe json output Signed-off-by: Nishant Bansal --- raster/r.describe/dumplist.c | 161 +++---- .../r.describe/testsuite/test_r_describe.py | 406 +++++++++++++----- 2 files changed, 390 insertions(+), 177 deletions(-) diff --git a/raster/r.describe/dumplist.c b/raster/r.describe/dumplist.c index de355e80ad3..b1ea54b20bf 100644 --- a/raster/r.describe/dumplist.c +++ b/raster/r.describe/dumplist.c @@ -22,11 +22,21 @@ #include "local_proto.h" -static int show(CELL, CELL, int *, DCELL, DCELL, RASTER_MAP_TYPE, int, - enum OutputFormat, JSON_Array *); +static void initialize_json_object(JSON_Value **, JSON_Object **); static void initialize_json_array(JSON_Value **, JSON_Array **); -static void json_append_category_value(JSON_Array *, const char *); +static void append_category_ranges(JSON_Array *range_array, long min, long max); static void output_pretty_json(JSON_Value *); +static int show(CELL, CELL, int *, DCELL, DCELL, RASTER_MAP_TYPE, int, + enum OutputFormat, JSON_Array *); + +void initialize_json_object(JSON_Value **root_value, JSON_Object **root_object) +{ + *root_value = json_value_init_object(); + if (*root_value == NULL) { + G_fatal_error(_("Failed to initialize JSON object. Out of memory?")); + } + *root_object = json_object(*root_value); +} void initialize_json_array(JSON_Value **root_value, JSON_Array **root_array) { @@ -37,19 +47,16 @@ void initialize_json_array(JSON_Value **root_value, JSON_Array **root_array) *root_array = json_array(*root_value); } -void json_append_category_value(JSON_Array *root_array, const char *cat_str) +void append_category_ranges(JSON_Array *range_array, long min, long max) { - JSON_Value *category_value; - JSON_Object *category; + JSON_Object *cat_object; + JSON_Value *cat_value; + initialize_json_object(&cat_value, &cat_object); - category_value = json_value_init_object(); - if (category_value == NULL) { - G_fatal_error(_("Failed to initialize JSON array. Out of memory?")); - } - category = json_object(category_value); + json_object_set_number(cat_object, "min", min); + json_object_set_number(cat_object, "max", max); - json_object_set_string(category, "value", cat_str); - json_array_append_value(root_array, category_value); + json_array_append_value(range_array, cat_value); } void output_pretty_json(JSON_Value *root_value) @@ -72,11 +79,13 @@ int long_list(struct Cell_stats *statf, DCELL dmin, DCELL dmax, CELL cat; long count; /* not used, but required by cell stats call */ char cat_str[MAX_STR_LEN]; - JSON_Value *root_value; - JSON_Array *root_array; + JSON_Value *root_value, *range_value; + JSON_Object *root_object; + JSON_Array *range_array; if (format == JSON) { - initialize_json_array(&root_value, &root_array); + initialize_json_object(&root_value, &root_object); + initialize_json_array(&range_value, &range_array); } Rast_get_stats_for_null_value(&count, statf); @@ -86,7 +95,7 @@ int long_list(struct Cell_stats *statf, DCELL dmin, DCELL dmax, fprintf(stdout, "%s\n", no_data_str); break; case JSON: - json_append_category_value(root_array, no_data_str); + json_object_set_string(root_object, "null_value", no_data_str); break; } } @@ -103,19 +112,35 @@ int long_list(struct Cell_stats *statf, DCELL dmin, DCELL dmax, break; case JSON: if (map_type != CELL_TYPE) { - snprintf(cat_str, sizeof(cat_str), "%f-%f", - dmin + (double)(cat - 1) * (dmax - dmin) / nsteps, - dmin + (double)cat * (dmax - dmin) / nsteps); + JSON_Object *cat_object; + JSON_Value *cat_value; + initialize_json_object(&cat_value, &cat_object); + + json_object_set_number(cat_object, "min", + dmin + (double)(cat - 1) * + (dmax - dmin) / nsteps); + json_object_set_number(cat_object, "max", + dmin + (double)cat * (dmax - dmin) / + nsteps); + + json_array_append_value(range_array, cat_value); } else { - snprintf(cat_str, sizeof(cat_str), "%ld", (long)cat); + json_array_append_number(range_array, (long)cat); } - json_append_category_value(root_array, cat_str); + break; } } if (format == JSON) { + if (map_type != CELL_TYPE) { + json_object_set_value(root_object, "ranges", range_value); + } + else { + json_object_set_value(root_object, "values", range_value); + } + output_pretty_json(root_value); } @@ -129,11 +154,13 @@ int compact_list(struct Cell_stats *statf, DCELL dmin, DCELL dmax, CELL cat1, cat2, temp; int len; long count; /* not used, but required by cell stats call */ - JSON_Value *root_value; - JSON_Array *root_array; + JSON_Value *root_value, *range_value; + JSON_Object *root_object; + JSON_Array *range_array; if (format == JSON) { - initialize_json_array(&root_value, &root_array); + initialize_json_object(&root_value, &root_object); + initialize_json_array(&range_value, &range_array); } len = 0; @@ -144,7 +171,7 @@ int compact_list(struct Cell_stats *statf, DCELL dmin, DCELL dmax, fprintf(stdout, "%s ", no_data_str); break; case JSON: - json_append_category_value(root_array, no_data_str); + json_object_set_string(root_object, "null_value", no_data_str); break; } } @@ -157,18 +184,19 @@ int compact_list(struct Cell_stats *statf, DCELL dmin, DCELL dmax, while (Rast_next_cell_stat(&temp, &count, statf)) { if (temp != cat2 + (CELL)1) { show(cat1, cat2, &len, dmin, dmax, map_type, nsteps, format, - root_array); + range_array); cat1 = temp; } cat2 = temp; } - show(cat1, cat2, &len, dmin, dmax, map_type, nsteps, format, root_array); + show(cat1, cat2, &len, dmin, dmax, map_type, nsteps, format, range_array); switch (format) { case PLAIN: fprintf(stdout, "\n"); break; case JSON: + json_object_set_value(root_object, "ranges", range_value); output_pretty_json(root_value); break; } @@ -182,6 +210,8 @@ static int show(CELL low, CELL high, int *len, DCELL dmin, DCELL dmax, { char text[MAX_STR_LEN]; char xlen; + JSON_Object *cat_object; + JSON_Value *cat_value; if (low + 1 == high) { show(low, low, len, dmin, dmax, map_type, nsteps, format, root_array); @@ -189,6 +219,9 @@ static int show(CELL low, CELL high, int *len, DCELL dmin, DCELL dmax, return 0; } + if (format == JSON) + initialize_json_object(&cat_value, &cat_object); + if (map_type != CELL_TYPE) { switch (format) { case PLAIN: @@ -197,9 +230,10 @@ static int show(CELL low, CELL high, int *len, DCELL dmin, DCELL dmax, dmin + high * (dmax - dmin) / nsteps); break; case JSON: - sprintf(text, "%f%s%f", dmin + (low - 1) * (dmax - dmin) / nsteps, - dmin < 0 ? " thru " : "-", - dmin + high * (dmax - dmin) / nsteps); + json_object_set_number(cat_object, "min", + dmin + (low - 1) * (dmax - dmin) / nsteps); + json_object_set_number(cat_object, "max", + dmin + high * (dmax - dmin) / nsteps); break; } } @@ -213,11 +247,8 @@ static int show(CELL low, CELL high, int *len, DCELL dmin, DCELL dmax, (long)high); break; case JSON: - if (low == high) - sprintf(text, "%ld", (long)low); - else - sprintf(text, "%ld%s%ld", (long)low, low < 0 ? " thru " : "-", - (long)high); + json_object_set_number(cat_object, "min", (long)low); + json_object_set_number(cat_object, "max", (long)high); break; } } @@ -234,7 +265,7 @@ static int show(CELL low, CELL high, int *len, DCELL dmin, DCELL dmax, fprintf(stdout, "%s", text); break; case JSON: - json_append_category_value(root_array, text); + json_array_append_value(root_array, cat_value); break; } @@ -247,11 +278,13 @@ int compact_range_list(CELL negmin, CELL negmax, CELL zero, CELL posmin, int skip_nulls, enum OutputFormat format) { char cat_str[MAX_STR_LEN]; - JSON_Value *root_value; - JSON_Array *root_array; + JSON_Value *root_value, *range_value; + JSON_Object *root_object; + JSON_Array *range_array; if (format == JSON) { - initialize_json_array(&root_value, &root_array); + initialize_json_object(&root_value, &root_object); + initialize_json_array(&range_value, &range_array); } if (negmin) { @@ -263,12 +296,7 @@ int compact_range_list(CELL negmin, CELL negmax, CELL zero, CELL posmin, fprintf(stdout, "\n"); break; case JSON: - snprintf(cat_str, sizeof(cat_str), "%ld", (long)negmin); - if (negmin != negmax) - snprintf(cat_str, sizeof(cat_str), "%ld thru %ld", (long)negmin, - (long)negmax); - - json_append_category_value(root_array, cat_str); + append_category_ranges(range_array, (long)negmin, (long)negmax); break; } } @@ -278,7 +306,7 @@ int compact_range_list(CELL negmin, CELL negmax, CELL zero, CELL posmin, fprintf(stdout, "0\n"); break; case JSON: - json_append_category_value(root_array, "0"); + append_category_ranges(range_array, 0, 0); break; } } @@ -291,12 +319,7 @@ int compact_range_list(CELL negmin, CELL negmax, CELL zero, CELL posmin, fprintf(stdout, "\n"); break; case JSON: - snprintf(cat_str, sizeof(cat_str), "%ld", (long)posmin); - if (posmin != posmax) - snprintf(cat_str, sizeof(cat_str), "%ld thru %ld", (long)posmin, - (long)posmax); - - json_append_category_value(root_array, cat_str); + append_category_ranges(range_array, (long)posmin, (long)posmax); break; } } @@ -307,12 +330,13 @@ int compact_range_list(CELL negmin, CELL negmax, CELL zero, CELL posmin, fprintf(stdout, "%s\n", no_data_str); break; case JSON: - json_append_category_value(root_array, no_data_str); + json_object_set_string(root_object, "null_value", no_data_str); break; } } if (format == JSON) { + json_object_set_value(root_object, "ranges", range_value); output_pretty_json(root_value); } @@ -324,11 +348,13 @@ int range_list(CELL negmin, CELL negmax, CELL zero, CELL posmin, CELL posmax, enum OutputFormat format) { char cat_str[MAX_STR_LEN]; - JSON_Value *root_value; - JSON_Array *root_array; + JSON_Value *root_value, *range_value; + JSON_Object *root_object; + JSON_Array *range_array; if (format == JSON) { - initialize_json_array(&root_value, &root_array); + initialize_json_object(&root_value, &root_object); + initialize_json_array(&range_value, &range_array); } if (negmin) { @@ -339,13 +365,7 @@ int range_list(CELL negmin, CELL negmax, CELL zero, CELL posmin, CELL posmax, fprintf(stdout, "%ld\n", (long)negmax); break; case JSON: - snprintf(cat_str, sizeof(cat_str), "%ld", (long)negmin); - json_append_category_value(root_array, cat_str); - - if (negmin != negmax) { - snprintf(cat_str, sizeof(cat_str), "%ld", (long)negmax); - json_append_category_value(root_array, cat_str); - } + append_category_ranges(range_array, (long)negmin, (long)negmax); break; } } @@ -356,7 +376,7 @@ int range_list(CELL negmin, CELL negmax, CELL zero, CELL posmin, CELL posmax, fprintf(stdout, "0\n"); break; case JSON: - json_append_category_value(root_array, "0"); + append_category_ranges(range_array, 0, 0); break; } } @@ -369,13 +389,7 @@ int range_list(CELL negmin, CELL negmax, CELL zero, CELL posmin, CELL posmax, fprintf(stdout, "%ld\n", (long)posmax); break; case JSON: - snprintf(cat_str, sizeof(cat_str), "%ld", (long)posmin); - json_append_category_value(root_array, cat_str); - - if (posmin != posmax) { - snprintf(cat_str, sizeof(cat_str), "%ld", (long)posmax); - json_append_category_value(root_array, cat_str); - } + append_category_ranges(range_array, (long)posmin, (long)posmax); break; } } @@ -386,12 +400,13 @@ int range_list(CELL negmin, CELL negmax, CELL zero, CELL posmin, CELL posmax, fprintf(stdout, "%s\n", no_data_str); break; case JSON: - json_append_category_value(root_array, no_data_str); + json_object_set_string(root_object, "null_value", no_data_str); break; } } if (format == JSON) { + json_object_set_value(root_object, "ranges", range_value); output_pretty_json(root_value); } diff --git a/raster/r.describe/testsuite/test_r_describe.py b/raster/r.describe/testsuite/test_r_describe.py index f1fbdf97daf..07f05d4220d 100644 --- a/raster/r.describe/testsuite/test_r_describe.py +++ b/raster/r.describe/testsuite/test_r_describe.py @@ -15,19 +15,26 @@ def setUpClass(cls): cls.runModule( "r.mapcalc", - expression="map = if(row() == 5 && col() == 5, null(), if(row() % 2 == 0, col() * 0.5, -col() * 0.5))", + expression="int_map = if(row() == 5 && col() == 5, null(), if(row() % 2 == 0, col(), -col()))", + overwrite=True, + ) + cls.runModule( + "r.mapcalc", + expression="float_map = if(row() == 5 && col() == 5, null(), if(row() % 2 == 0, col() * 0.5, -col() * 0.5))", overwrite=True, ) @classmethod def tearDownClass(cls): """Clean up after tests.""" - cls.runModule("g.remove", flags="f", type="raster", name=["map"]) + cls.runModule( + "g.remove", flags="f", type="raster", name=["int_map", "float_map"] + ) cls.del_temp_region() - def test_plain_describe(self): - """Test r.describe with the default output format.""" - module = SimpleModule("r.describe", map="map") + def test_plain_describe_float(self): + """Test r.describe with the default output format and a float-type map.""" + module = SimpleModule("r.describe", map="float_map") self.assertModule(module) result = module.outputs.stdout.strip().splitlines() @@ -47,9 +54,9 @@ def test_plain_describe(self): component, expected_results[i], f"Mismatch at line {i + 1}" ) - def test_plain_describe_with_one_flag(self): - """Test r.describe with the plain output format and the -1 flag.""" - module = SimpleModule("r.describe", map="map", flags="1") + def test_plain_describe_with_one_flag_float(self): + """Test r.describe with the plain output format, the -1 flag, and a float-type map""" + module = SimpleModule("r.describe", map="float_map", flags="1") self.assertModule(module) result = module.outputs.stdout.strip().splitlines() @@ -83,9 +90,9 @@ def test_plain_describe_with_one_flag(self): component, expected_results[i], f"Mismatch at line {i + 1}" ) - def test_plain_describe_with_r_flag(self): - """Test r.describe with the plain output format and the -r flag.""" - module = SimpleModule("r.describe", map="map", flags="r") + def test_plain_describe_with_r_flag_float(self): + """Test r.describe with the plain output format, the -r flag, and a float-type map""" + module = SimpleModule("r.describe", map="float_map", flags="r") self.assertModule(module) result = module.outputs.stdout.strip().splitlines() @@ -97,9 +104,9 @@ def test_plain_describe_with_r_flag(self): component, expected_results[i], f"Mismatch at line {i + 1}" ) - def test_plain_describe_with_i_flag(self): - """Test r.describe with the plain output format and the -i flag.""" - module = SimpleModule("r.describe", map="map", flags="i") + def test_plain_describe_with_i_flag_float(self): + """Test r.describe with the plain output format, the -i flag, and a float-type map""" + module = SimpleModule("r.describe", map="float_map", flags="i") self.assertModule(module) result = module.outputs.stdout.strip().splitlines() @@ -111,9 +118,9 @@ def test_plain_describe_with_i_flag(self): component, expected_results[i], f"Mismatch at line {i + 1}" ) - def test_plain_describe_with_n_flag(self): - """Test r.describe with the plain output format and the -n flag.""" - module = SimpleModule("r.describe", map="map", flags="n") + def test_plain_describe_with_n_flag_float(self): + """Test r.describe with the plain output format, the -n flag, and a float-type map""" + module = SimpleModule("r.describe", map="float_map", flags="n") self.assertModule(module) result = module.outputs.stdout.strip().splitlines() @@ -133,125 +140,316 @@ def test_plain_describe_with_n_flag(self): component, expected_results[i], f"Mismatch at line {i + 1}" ) - def test_json_describe(self): - """Test r.describe with the json output format.""" - module = SimpleModule("r.describe", map="map", format="json") + def test_json_describe_float(self): + """Test r.describe with the json output format, and a float-type map""" + module = SimpleModule("r.describe", map="float_map", format="json") + self.assertModule(module) + + result = json.loads(module.outputs.stdout) + + expected_results = { + "null_value": "*", + "ranges": [ + {"min": -5, "max": -4.96078431372549}, + {"min": -4.529411764705882, "max": -4.490196078431373}, + {"min": -4.019607843137255, "max": -3.980392156862745}, + {"min": -3.5098039215686274, "max": -3.4705882352941178}, + {"min": -3.0392156862745097, "max": -3}, + {"min": -2.5294117647058822, "max": -2.4901960784313726}, + {"min": -2.019607843137255, "max": -1.9803921568627452}, + {"min": -1.549019607843137, "max": -1.5098039215686274}, + {"min": -1.0392156862745097, "max": -1}, + {"min": -0.5294117647058822, "max": -0.4901960784313726}, + {"min": 0.4509803921568629, "max": 0.4901960784313726}, + {"min": 0.9607843137254903, "max": 1}, + {"min": 1.4705882352941178, "max": 1.5098039215686274}, + {"min": 1.9411764705882355, "max": 1.9803921568627452}, + {"min": 2.450980392156863, "max": 2.4901960784313726}, + {"min": 2.9607843137254903, "max": 3}, + {"min": 3.431372549019608, "max": 3.4705882352941178}, + {"min": 3.9411764705882355, "max": 3.980392156862745}, + {"min": 4.450980392156863, "max": 4.490196078431373}, + {"min": 4.96078431372549, "max": 5}, + ], + } + + self.assertDictEqual(expected_results, result) + + def test_json_describe_with_one_flag_float(self): + """Test r.describe with the json output format, the -1 flag, and a float-type map""" + module = SimpleModule("r.describe", map="float_map", flags="1", format="json") + self.assertModule(module) + + result = json.loads(module.outputs.stdout) + + expected_results = { + "null_value": "*", + "ranges": [ + {"min": -5, "max": -4.96078431372549}, + {"min": -4.529411764705882, "max": -4.490196078431373}, + {"min": -4.019607843137255, "max": -3.980392156862745}, + {"min": -3.5098039215686274, "max": -3.4705882352941178}, + {"min": -3.0392156862745097, "max": -3}, + {"min": -2.5294117647058822, "max": -2.4901960784313726}, + {"min": -2.019607843137255, "max": -1.9803921568627452}, + {"min": -1.549019607843137, "max": -1.5098039215686274}, + {"min": -1.0392156862745097, "max": -1}, + {"min": -0.5294117647058822, "max": -0.4901960784313726}, + {"min": 0.4509803921568629, "max": 0.4901960784313726}, + {"min": 0.9607843137254903, "max": 1}, + {"min": 1.4705882352941178, "max": 1.5098039215686274}, + {"min": 1.9411764705882355, "max": 1.9803921568627452}, + {"min": 2.450980392156863, "max": 2.4901960784313726}, + {"min": 2.9607843137254903, "max": 3}, + {"min": 3.431372549019608, "max": 3.4705882352941178}, + {"min": 3.9411764705882355, "max": 3.980392156862745}, + {"min": 4.450980392156863, "max": 4.490196078431373}, + {"min": 4.96078431372549, "max": 5}, + ], + } + + self.assertDictEqual(expected_results, result) + + def test_json_describe_with_r_flag_float(self): + """Test r.describe with the json output format, the -r flag, and a float-type map""" + module = SimpleModule("r.describe", map="float_map", flags="r", format="json") self.assertModule(module) result = json.loads(module.outputs.stdout) + expected_results = {"null_value": "*", "ranges": [{"min": -5, "max": 5}]} + + self.assertDictEqual(expected_results, result) + + def test_json_describe_with_i_flag_float(self): + """Test r.describe with the json output format and the -i flag.""" + module = SimpleModule("r.describe", map="float_map", flags="i", format="json") + self.assertModule(module) + + result = json.loads(module.outputs.stdout) + + expected_results = { + "null_value": "*", + "ranges": [{"min": -5, "max": -1}, {"min": 1, "max": 5}], + } + + self.assertDictEqual(expected_results, result) + + def test_json_describe_with_n_flag_float(self): + """Test r.describe with the json output format, the -n flag, and a float-type map""" + module = SimpleModule("r.describe", map="float_map", flags="n", format="json") + self.assertModule(module) + + result = json.loads(module.outputs.stdout) + + expected_results = { + "ranges": [ + {"min": -5, "max": -4.96078431372549}, + {"min": -4.529411764705882, "max": -4.490196078431373}, + {"min": -4.019607843137255, "max": -3.980392156862745}, + {"min": -3.5098039215686274, "max": -3.4705882352941178}, + {"min": -3.0392156862745097, "max": -3}, + {"min": -2.5294117647058822, "max": -2.4901960784313726}, + {"min": -2.019607843137255, "max": -1.9803921568627452}, + {"min": -1.549019607843137, "max": -1.5098039215686274}, + {"min": -1.0392156862745097, "max": -1}, + {"min": -0.5294117647058822, "max": -0.4901960784313726}, + {"min": 0.4509803921568629, "max": 0.4901960784313726}, + {"min": 0.9607843137254903, "max": 1}, + {"min": 1.4705882352941178, "max": 1.5098039215686274}, + {"min": 1.9411764705882355, "max": 1.9803921568627452}, + {"min": 2.450980392156863, "max": 2.4901960784313726}, + {"min": 2.9607843137254903, "max": 3}, + {"min": 3.431372549019608, "max": 3.4705882352941178}, + {"min": 3.9411764705882355, "max": 3.980392156862745}, + {"min": 4.450980392156863, "max": 4.490196078431373}, + {"min": 4.96078431372549, "max": 5}, + ] + } + + self.assertDictEqual(expected_results, result) + + def test_plain_describe_int(self): + """Test r.describe with the default output format, and a int-type map""" + module = SimpleModule("r.describe", map="int_map") + self.assertModule(module) + + result = module.outputs.stdout.strip().splitlines() + expected_results = [ - {"value": "*"}, - {"value": "-5.000000 thru -4.960784"}, - {"value": "-4.529412 thru -4.490196"}, - {"value": "-4.019608 thru -3.980392"}, - {"value": "-3.509804 thru -3.470588"}, - {"value": "-3.039216 thru -3.000000"}, - {"value": "-2.529412 thru -2.490196"}, - {"value": "-2.019608 thru -1.980392"}, - {"value": "-1.549020 thru -1.509804"}, - {"value": "-1.039216 thru -1.000000"}, - {"value": "-0.529412 thru -0.490196"}, - {"value": "0.450980 thru 0.490196"}, - {"value": "0.960784 thru 1.000000"}, - {"value": "1.470588 thru 1.509804"}, - {"value": "1.941176 thru 1.980392"}, - {"value": "2.450980 thru 2.490196"}, - {"value": "2.960784 thru 3.000000"}, - {"value": "3.431373 thru 3.470588"}, - {"value": "3.941176 thru 3.980392"}, - {"value": "4.450980 thru 4.490196"}, - {"value": "4.960784 thru 5.000000"}, + "* -10 thru -1 1-10", ] - self.assertListEqual(expected_results, result) + for i, component in enumerate(result): + self.assertEqual( + component, expected_results[i], f"Mismatch at line {i + 1}" + ) - def test_json_describe_with_one_flag(self): - """Test r.describe with the json output format and the -1 flag.""" - module = SimpleModule("r.describe", map="map", flags="1", format="json") + def test_plain_describe_with_one_flag_int(self): + """Test r.describe with the plain output format, the -1 flag, and a int-type map""" + module = SimpleModule("r.describe", map="int_map", flags="1") self.assertModule(module) - result = json.loads(module.outputs.stdout) + result = module.outputs.stdout.strip().splitlines() expected_results = [ - {"value": "*"}, - {"value": "-5.000000--4.960784"}, - {"value": "-4.529412--4.490196"}, - {"value": "-4.019608--3.980392"}, - {"value": "-3.509804--3.470588"}, - {"value": "-3.039216--3.000000"}, - {"value": "-2.529412--2.490196"}, - {"value": "-2.019608--1.980392"}, - {"value": "-1.549020--1.509804"}, - {"value": "-1.039216--1.000000"}, - {"value": "-0.529412--0.490196"}, - {"value": "0.450980-0.490196"}, - {"value": "0.960784-1.000000"}, - {"value": "1.470588-1.509804"}, - {"value": "1.941176-1.980392"}, - {"value": "2.450980-2.490196"}, - {"value": "2.960784-3.000000"}, - {"value": "3.431373-3.470588"}, - {"value": "3.941176-3.980392"}, - {"value": "4.450980-4.490196"}, - {"value": "4.960784-5.000000"}, + "*", + "-10", + "-9", + "-8", + "-7", + "-6", + "-5", + "-4", + "-3", + "-2", + "-1", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", ] - self.assertListEqual(expected_results, result) + for i, component in enumerate(result): + self.assertEqual( + component, expected_results[i], f"Mismatch at line {i + 1}" + ) - def test_json_describe_with_r_flag(self): - """Test r.describe with the json output format and the -r flag.""" - module = SimpleModule("r.describe", map="map", flags="r", format="json") + def test_plain_describe_with_r_flag_int(self): + """Test r.describe with the plain output format, the -r flag, and a int-type map""" + module = SimpleModule("r.describe", map="int_map", flags="r") + self.assertModule(module) + + result = module.outputs.stdout.strip().splitlines() + + expected_results = ["-10 thru -1", "1 thru 10", "*"] + + for i, component in enumerate(result): + self.assertEqual( + component, expected_results[i], f"Mismatch at line {i + 1}" + ) + + def test_plain_describe_with_i_flag_int(self): + """Test r.describe with the plain output format, the -i flag, and a int-type map""" + module = SimpleModule("r.describe", map="int_map", flags="i") + self.assertModule(module) + + result = module.outputs.stdout.strip().splitlines() + + expected_results = ["* -10 thru -1 1-10"] + + for i, component in enumerate(result): + self.assertEqual( + component, expected_results[i], f"Mismatch at line {i + 1}" + ) + + def test_plain_describe_with_n_flag_int(self): + """Test r.describe with the plain output format, the -n flag, and a int-type map""" + module = SimpleModule("r.describe", map="int_map", flags="n") + self.assertModule(module) + + result = module.outputs.stdout.strip().splitlines() + + expected_results = ["-10 thru -1 1-10"] + + for i, component in enumerate(result): + self.assertEqual( + component, expected_results[i], f"Mismatch at line {i + 1}" + ) + + def test_json_describe_int(self): + """Test r.describe with the json output format, and a int-type map""" + module = SimpleModule("r.describe", map="int_map", format="json") self.assertModule(module) result = json.loads(module.outputs.stdout) - expected_results = [{"value": "*"}, {"value": "-5.000000 thru 5.000000"}] + expected_results = { + "null_value": "*", + "ranges": [{"min": -10, "max": -1}, {"min": 1, "max": 10}], + } - self.assertListEqual(expected_results, result) + self.assertDictEqual(expected_results, result) - def test_json_describe_with_i_flag(self): - """Test r.describe with the json output format and the -i flag.""" - module = SimpleModule("r.describe", map="map", flags="i", format="json") + def test_json_describe_with_one_flag_int(self): + """Test r.describe with the json output format, the -1 flag, and a int-type map""" + module = SimpleModule("r.describe", map="int_map", flags="1", format="json") self.assertModule(module) result = json.loads(module.outputs.stdout) - expected_results = [{"value": "*"}, {"value": "-5 thru -1"}, {"value": "1-5"}] + expected_results = { + "null_value": "*", + "values": [ + -10, + -9, + -8, + -7, + -6, + -5, + -4, + -3, + -2, + -1, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + ], + } + + self.assertDictEqual(expected_results, result) + + def test_json_describe_with_r_flag_int(self): + """Test r.describe with the json output format, the -r flag, and a int-type map""" + module = SimpleModule("r.describe", map="int_map", flags="r", format="json") + self.assertModule(module) - self.assertListEqual(expected_results, result) + result = json.loads(module.outputs.stdout) - def test_json_describe_with_n_flag(self): - """Test r.describe with the json output format and the -n flag.""" - module = SimpleModule("r.describe", map="map", flags="n", format="json") + expected_results = { + "null_value": "*", + "ranges": [{"min": -10, "max": -1}, {"min": 1, "max": 10}], + } + + self.assertDictEqual(expected_results, result) + + def test_json_describe_with_i_flag_int(self): + """Test r.describe with the json output format, the -i flag, and a int-type map""" + module = SimpleModule("r.describe", map="int_map", flags="i", format="json") self.assertModule(module) result = json.loads(module.outputs.stdout) - expected_results = [ - {"value": "-5.000000 thru -4.960784"}, - {"value": "-4.529412 thru -4.490196"}, - {"value": "-4.019608 thru -3.980392"}, - {"value": "-3.509804 thru -3.470588"}, - {"value": "-3.039216 thru -3.000000"}, - {"value": "-2.529412 thru -2.490196"}, - {"value": "-2.019608 thru -1.980392"}, - {"value": "-1.549020 thru -1.509804"}, - {"value": "-1.039216 thru -1.000000"}, - {"value": "-0.529412 thru -0.490196"}, - {"value": "0.450980 thru 0.490196"}, - {"value": "0.960784 thru 1.000000"}, - {"value": "1.470588 thru 1.509804"}, - {"value": "1.941176 thru 1.980392"}, - {"value": "2.450980 thru 2.490196"}, - {"value": "2.960784 thru 3.000000"}, - {"value": "3.431373 thru 3.470588"}, - {"value": "3.941176 thru 3.980392"}, - {"value": "4.450980 thru 4.490196"}, - {"value": "4.960784 thru 5.000000"}, - ] + expected_results = { + "null_value": "*", + "ranges": [{"min": -10, "max": -1}, {"min": 1, "max": 10}], + } + + self.assertDictEqual(expected_results, result) + + def test_json_describe_with_n_flag_int(self): + """Test r.describe with the json output format, the -n flag, and a int-type map""" + module = SimpleModule("r.describe", map="int_map", flags="n", format="json") + self.assertModule(module) + + result = json.loads(module.outputs.stdout) + + expected_results = {"ranges": [{"min": -10, "max": -1}, {"min": 1, "max": 10}]} - self.assertListEqual(expected_results, result) + self.assertDictEqual(expected_results, result) if __name__ == "__main__": From e8b9dd95135fcb037c7131d9cb680013b4abcb4b Mon Sep 17 00:00:00 2001 From: Nishant Bansal Date: Thu, 16 Jan 2025 16:03:09 +0530 Subject: [PATCH 5/7] remove unused variables Signed-off-by: Nishant Bansal --- raster/r.describe/dumplist.c | 3 --- raster/r.describe/local_proto.h | 2 -- 2 files changed, 5 deletions(-) diff --git a/raster/r.describe/dumplist.c b/raster/r.describe/dumplist.c index b1ea54b20bf..c3627d40684 100644 --- a/raster/r.describe/dumplist.c +++ b/raster/r.describe/dumplist.c @@ -78,7 +78,6 @@ int long_list(struct Cell_stats *statf, DCELL dmin, DCELL dmax, { CELL cat; long count; /* not used, but required by cell stats call */ - char cat_str[MAX_STR_LEN]; JSON_Value *root_value, *range_value; JSON_Object *root_object; JSON_Array *range_array; @@ -277,7 +276,6 @@ int compact_range_list(CELL negmin, CELL negmax, CELL zero, CELL posmin, CELL posmax, CELL null, char *no_data_str, int skip_nulls, enum OutputFormat format) { - char cat_str[MAX_STR_LEN]; JSON_Value *root_value, *range_value; JSON_Object *root_object; JSON_Array *range_array; @@ -347,7 +345,6 @@ int range_list(CELL negmin, CELL negmax, CELL zero, CELL posmin, CELL posmax, CELL null, char *no_data_str, int skip_nulls, enum OutputFormat format) { - char cat_str[MAX_STR_LEN]; JSON_Value *root_value, *range_value; JSON_Object *root_object; JSON_Array *range_array; diff --git a/raster/r.describe/local_proto.h b/raster/r.describe/local_proto.h index 0ebbec32bc1..ecf51473899 100644 --- a/raster/r.describe/local_proto.h +++ b/raster/r.describe/local_proto.h @@ -21,8 +21,6 @@ #include #include -#define MAX_STR_LEN 100 - enum OutputFormat { PLAIN, JSON }; /* describe.c */ From 777ca18dd8bfe056f0744b3f16193802369c220f Mon Sep 17 00:00:00 2001 From: Nishant Bansal Date: Thu, 16 Jan 2025 16:12:50 +0530 Subject: [PATCH 6/7] fixes CI issues Signed-off-by: Nishant Bansal --- raster/r.describe/dumplist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/raster/r.describe/dumplist.c b/raster/r.describe/dumplist.c index c3627d40684..ed1b2a5c43c 100644 --- a/raster/r.describe/dumplist.c +++ b/raster/r.describe/dumplist.c @@ -207,7 +207,7 @@ static int show(CELL low, CELL high, int *len, DCELL dmin, DCELL dmax, RASTER_MAP_TYPE map_type, int nsteps, enum OutputFormat format, JSON_Array *root_array) { - char text[MAX_STR_LEN]; + char text[100]; char xlen; JSON_Object *cat_object; JSON_Value *cat_value; From 6e3a5c173b519c343c3c1f79c4db3661815d94ef Mon Sep 17 00:00:00 2001 From: Nishant Bansal Date: Wed, 22 Jan 2025 14:56:30 +0530 Subject: [PATCH 7/7] use has_nulls instead of null_value Signed-off-by: Nishant Bansal --- raster/r.describe/dumplist.c | 92 ++++++++++++------- .../r.describe/testsuite/test_r_describe.py | 25 +++-- 2 files changed, 72 insertions(+), 45 deletions(-) diff --git a/raster/r.describe/dumplist.c b/raster/r.describe/dumplist.c index ed1b2a5c43c..890e875d32e 100644 --- a/raster/r.describe/dumplist.c +++ b/raster/r.describe/dumplist.c @@ -88,14 +88,21 @@ int long_list(struct Cell_stats *statf, DCELL dmin, DCELL dmax, } Rast_get_stats_for_null_value(&count, statf); - if (count != 0 && !skip_nulls) { - switch (format) { - case PLAIN: - fprintf(stdout, "%s\n", no_data_str); - break; - case JSON: - json_object_set_string(root_object, "null_value", no_data_str); - break; + if (!skip_nulls) { + if (count != 0) { + switch (format) { + case PLAIN: + fprintf(stdout, "%s\n", no_data_str); + break; + case JSON: + json_object_set_boolean(root_object, "has_nulls", true); + break; + } + } + else { + if (format == JSON) { + json_object_set_boolean(root_object, "has_nulls", false); + } } } @@ -164,14 +171,21 @@ int compact_list(struct Cell_stats *statf, DCELL dmin, DCELL dmax, len = 0; Rast_get_stats_for_null_value(&count, statf); - if (count != 0 && !skip_nulls) { - switch (format) { - case PLAIN: - fprintf(stdout, "%s ", no_data_str); - break; - case JSON: - json_object_set_string(root_object, "null_value", no_data_str); - break; + if (!skip_nulls) { + if (count != 0) { + switch (format) { + case PLAIN: + fprintf(stdout, "%s ", no_data_str); + break; + case JSON: + json_object_set_boolean(root_object, "has_nulls", true); + break; + } + } + else { + if (format == JSON) { + json_object_set_boolean(root_object, "has_nulls", false); + } } } @@ -322,14 +336,21 @@ int compact_range_list(CELL negmin, CELL negmax, CELL zero, CELL posmin, } } - if (null && !skip_nulls) { - switch (format) { - case PLAIN: - fprintf(stdout, "%s\n", no_data_str); - break; - case JSON: - json_object_set_string(root_object, "null_value", no_data_str); - break; + if (!skip_nulls) { + if (null) { + switch (format) { + case PLAIN: + fprintf(stdout, "%s\n", no_data_str); + break; + case JSON: + json_object_set_boolean(root_object, "has_nulls", true); + break; + } + } + else { + if (format == JSON) { + json_object_set_boolean(root_object, "has_nulls", false); + } } } @@ -391,14 +412,21 @@ int range_list(CELL negmin, CELL negmax, CELL zero, CELL posmin, CELL posmax, } } - if (null && !skip_nulls) { - switch (format) { - case PLAIN: - fprintf(stdout, "%s\n", no_data_str); - break; - case JSON: - json_object_set_string(root_object, "null_value", no_data_str); - break; + if (!skip_nulls) { + if (null) { + switch (format) { + case PLAIN: + fprintf(stdout, "%s\n", no_data_str); + break; + case JSON: + json_object_set_boolean(root_object, "has_nulls", true); + break; + } + } + else { + if (format == JSON) { + json_object_set_boolean(root_object, "has_nulls", false); + } } } diff --git a/raster/r.describe/testsuite/test_r_describe.py b/raster/r.describe/testsuite/test_r_describe.py index 07f05d4220d..34e647a4d12 100644 --- a/raster/r.describe/testsuite/test_r_describe.py +++ b/raster/r.describe/testsuite/test_r_describe.py @@ -15,7 +15,7 @@ def setUpClass(cls): cls.runModule( "r.mapcalc", - expression="int_map = if(row() == 5 && col() == 5, null(), if(row() % 2 == 0, col(), -col()))", + expression="int_map = if(row() % 2 == 0, col(), -col())", overwrite=True, ) cls.runModule( @@ -148,7 +148,7 @@ def test_json_describe_float(self): result = json.loads(module.outputs.stdout) expected_results = { - "null_value": "*", + "has_nulls": True, "ranges": [ {"min": -5, "max": -4.96078431372549}, {"min": -4.529411764705882, "max": -4.490196078431373}, @@ -183,7 +183,7 @@ def test_json_describe_with_one_flag_float(self): result = json.loads(module.outputs.stdout) expected_results = { - "null_value": "*", + "has_nulls": True, "ranges": [ {"min": -5, "max": -4.96078431372549}, {"min": -4.529411764705882, "max": -4.490196078431373}, @@ -217,7 +217,7 @@ def test_json_describe_with_r_flag_float(self): result = json.loads(module.outputs.stdout) - expected_results = {"null_value": "*", "ranges": [{"min": -5, "max": 5}]} + expected_results = {"has_nulls": True, "ranges": [{"min": -5, "max": 5}]} self.assertDictEqual(expected_results, result) @@ -229,7 +229,7 @@ def test_json_describe_with_i_flag_float(self): result = json.loads(module.outputs.stdout) expected_results = { - "null_value": "*", + "has_nulls": True, "ranges": [{"min": -5, "max": -1}, {"min": 1, "max": 5}], } @@ -277,7 +277,7 @@ def test_plain_describe_int(self): result = module.outputs.stdout.strip().splitlines() expected_results = [ - "* -10 thru -1 1-10", + "-10 thru -1 1-10", ] for i, component in enumerate(result): @@ -293,7 +293,6 @@ def test_plain_describe_with_one_flag_int(self): result = module.outputs.stdout.strip().splitlines() expected_results = [ - "*", "-10", "-9", "-8", @@ -328,7 +327,7 @@ def test_plain_describe_with_r_flag_int(self): result = module.outputs.stdout.strip().splitlines() - expected_results = ["-10 thru -1", "1 thru 10", "*"] + expected_results = ["-10 thru -1", "1 thru 10"] for i, component in enumerate(result): self.assertEqual( @@ -342,7 +341,7 @@ def test_plain_describe_with_i_flag_int(self): result = module.outputs.stdout.strip().splitlines() - expected_results = ["* -10 thru -1 1-10"] + expected_results = ["-10 thru -1 1-10"] for i, component in enumerate(result): self.assertEqual( @@ -371,7 +370,7 @@ def test_json_describe_int(self): result = json.loads(module.outputs.stdout) expected_results = { - "null_value": "*", + "has_nulls": False, "ranges": [{"min": -10, "max": -1}, {"min": 1, "max": 10}], } @@ -385,7 +384,7 @@ def test_json_describe_with_one_flag_int(self): result = json.loads(module.outputs.stdout) expected_results = { - "null_value": "*", + "has_nulls": False, "values": [ -10, -9, @@ -420,7 +419,7 @@ def test_json_describe_with_r_flag_int(self): result = json.loads(module.outputs.stdout) expected_results = { - "null_value": "*", + "has_nulls": False, "ranges": [{"min": -10, "max": -1}, {"min": 1, "max": 10}], } @@ -434,7 +433,7 @@ def test_json_describe_with_i_flag_int(self): result = json.loads(module.outputs.stdout) expected_results = { - "null_value": "*", + "has_nulls": False, "ranges": [{"min": -10, "max": -1}, {"min": 1, "max": 10}], }