diff --git a/lib/raster/json_color_out.c b/lib/raster/json_color_out.c index f5073f9f13f..3f9e69e6f2d 100644 --- a/lib/raster/json_color_out.c +++ b/lib/raster/json_color_out.c @@ -99,24 +99,24 @@ static void set_color(int r, int g, int b, ColorFormat clr_frmt, case RGB: snprintf(color_string, sizeof(color_string), "rgb(%d, %d, %d)", r, g, b); - G_json_object_set_string(color_object, "rgb", color_string); + G_json_object_set_string(color_object, "color", color_string); break; case HEX: snprintf(color_string, sizeof(color_string), "#%02X%02X%02X", r, g, b); - G_json_object_set_string(color_object, "hex", color_string); + G_json_object_set_string(color_object, "color", color_string); break; case HSV: rgb_to_hsv(r, g, b, &h, &s, &v); snprintf(color_string, sizeof(color_string), "hsv(%d, %d, %d)", (int)h, (int)s, (int)v); - G_json_object_set_string(color_object, "hsv", color_string); + G_json_object_set_string(color_object, "color", color_string); break; case TRIPLET: snprintf(color_string, sizeof(color_string), "%d:%d:%d", r, g, b); - G_json_object_set_string(color_object, "triplet", color_string); + G_json_object_set_string(color_object, "color", color_string); break; } } diff --git a/raster/r.colors.out/tests/r3_colors_out_test.py b/raster/r.colors.out/tests/r3_colors_out_test.py index 670c1ef13a6..463aad14dbf 100644 --- a/raster/r.colors.out/tests/r3_colors_out_test.py +++ b/raster/r.colors.out/tests/r3_colors_out_test.py @@ -71,14 +71,14 @@ def test_r3_colors_out_json_with_default_option(raster3_color_dataset): data = gs.parse_command("r3.colors.out", map="b", format="json", env=session.env) validate_common_json_structure(data) expected = [ - {"value": 1, "hex": "#00BFBF"}, - {"value": 1.8, "hex": "#00FF00"}, - {"value": 2.6, "hex": "#FFFF00"}, - {"value": 3.4, "hex": "#FF7F00"}, - {"value": 4.2, "hex": "#BF7F3F"}, - {"value": 5, "hex": "#C8C8C8"}, - {"value": "nv", "hex": "#FFFFFF"}, - {"value": "default", "hex": "#FFFFFF"}, + {"value": 1, "color": "#00BFBF"}, + {"value": 1.8, "color": "#00FF00"}, + {"value": 2.6, "color": "#FFFF00"}, + {"value": 3.4, "color": "#FF7F00"}, + {"value": 4.2, "color": "#BF7F3F"}, + {"value": 5, "color": "#C8C8C8"}, + {"value": "nv", "color": "#FFFFFF"}, + {"value": "default", "color": "#FFFFFF"}, ] assert expected == data, f"test failed: expected {expected} but got {data}" @@ -91,14 +91,14 @@ def test_r3_colors_out_json_with_triplet_option(raster3_color_dataset): ) validate_common_json_structure(data) expected = [ - {"value": 1, "triplet": "0:191:191"}, - {"value": 1.8, "triplet": "0:255:0"}, - {"value": 2.6, "triplet": "255:255:0"}, - {"value": 3.4, "triplet": "255:127:0"}, - {"value": 4.2, "triplet": "191:127:63"}, - {"value": 5, "triplet": "200:200:200"}, - {"value": "nv", "triplet": "255:255:255"}, - {"value": "default", "triplet": "255:255:255"}, + {"value": 1, "color": "0:191:191"}, + {"value": 1.8, "color": "0:255:0"}, + {"value": 2.6, "color": "255:255:0"}, + {"value": 3.4, "color": "255:127:0"}, + {"value": 4.2, "color": "191:127:63"}, + {"value": 5, "color": "200:200:200"}, + {"value": "nv", "color": "255:255:255"}, + {"value": "default", "color": "255:255:255"}, ] assert expected == data, f"test failed: expected {expected} but got {data}" @@ -115,14 +115,14 @@ def test_r3_colors_out_json_with_rgb_option(raster3_color_dataset): ) validate_common_json_structure(data) expected = [ - {"value": 1, "rgb": "rgb(0, 191, 191)"}, - {"value": 1.8, "rgb": "rgb(0, 255, 0)"}, - {"value": 2.6, "rgb": "rgb(255, 255, 0)"}, - {"value": 3.4, "rgb": "rgb(255, 127, 0)"}, - {"value": 4.2, "rgb": "rgb(191, 127, 63)"}, - {"value": 5, "rgb": "rgb(200, 200, 200)"}, - {"value": "nv", "rgb": "rgb(255, 255, 255)"}, - {"value": "default", "rgb": "rgb(255, 255, 255)"}, + {"value": 1, "color": "rgb(0, 191, 191)"}, + {"value": 1.8, "color": "rgb(0, 255, 0)"}, + {"value": 2.6, "color": "rgb(255, 255, 0)"}, + {"value": 3.4, "color": "rgb(255, 127, 0)"}, + {"value": 4.2, "color": "rgb(191, 127, 63)"}, + {"value": 5, "color": "rgb(200, 200, 200)"}, + {"value": "nv", "color": "rgb(255, 255, 255)"}, + {"value": "default", "color": "rgb(255, 255, 255)"}, ] assert expected == data, f"test failed: expected {expected} but got {data}" @@ -139,14 +139,14 @@ def test_r3_colors_out_json_with_hex_option(raster3_color_dataset): ) validate_common_json_structure(data) expected = [ - {"value": 1, "hex": "#00BFBF"}, - {"value": 1.8, "hex": "#00FF00"}, - {"value": 2.6, "hex": "#FFFF00"}, - {"value": 3.4, "hex": "#FF7F00"}, - {"value": 4.2, "hex": "#BF7F3F"}, - {"value": 5, "hex": "#C8C8C8"}, - {"value": "nv", "hex": "#FFFFFF"}, - {"value": "default", "hex": "#FFFFFF"}, + {"value": 1, "color": "#00BFBF"}, + {"value": 1.8, "color": "#00FF00"}, + {"value": 2.6, "color": "#FFFF00"}, + {"value": 3.4, "color": "#FF7F00"}, + {"value": 4.2, "color": "#BF7F3F"}, + {"value": 5, "color": "#C8C8C8"}, + {"value": "nv", "color": "#FFFFFF"}, + {"value": "default", "color": "#FFFFFF"}, ] assert expected == data, f"test failed: expected {expected} but got {data}" @@ -163,13 +163,13 @@ def test_r3_colors_out_json_with_hsv_option(raster3_color_dataset): ) validate_common_json_structure(data) expected = [ - {"value": 1, "hsv": "hsv(180, 100, 74)"}, - {"value": 1.8, "hsv": "hsv(120, 100, 100)"}, - {"value": 2.6, "hsv": "hsv(60, 100, 100)"}, - {"value": 3.4, "hsv": "hsv(29, 100, 100)"}, - {"value": 4.2, "hsv": "hsv(30, 67, 74)"}, - {"value": 5, "hsv": "hsv(0, 0, 78)"}, - {"value": "nv", "hsv": "hsv(0, 0, 100)"}, - {"value": "default", "hsv": "hsv(0, 0, 100)"}, + {"value": 1, "color": "hsv(180, 100, 74)"}, + {"value": 1.8, "color": "hsv(120, 100, 100)"}, + {"value": 2.6, "color": "hsv(60, 100, 100)"}, + {"value": 3.4, "color": "hsv(29, 100, 100)"}, + {"value": 4.2, "color": "hsv(30, 67, 74)"}, + {"value": 5, "color": "hsv(0, 0, 78)"}, + {"value": "nv", "color": "hsv(0, 0, 100)"}, + {"value": "default", "color": "hsv(0, 0, 100)"}, ] assert expected == data, f"test failed: expected {expected} but got {data}" diff --git a/raster/r.colors.out/tests/r_colors_out_test.py b/raster/r.colors.out/tests/r_colors_out_test.py index d1abec82592..91d0452e530 100644 --- a/raster/r.colors.out/tests/r_colors_out_test.py +++ b/raster/r.colors.out/tests/r_colors_out_test.py @@ -71,14 +71,14 @@ def test_r_colors_out_json_with_default_option(raster_color_dataset): data = gs.parse_command("r.colors.out", map="a", format="json", env=session.env) validate_common_json_structure(data) expected = [ - {"value": 1, "hex": "#00BFBF"}, - {"value": 1.4, "hex": "#00FF00"}, - {"value": 1.8, "hex": "#FFFF00"}, - {"value": 2.2, "hex": "#FF7F00"}, - {"value": 2.6, "hex": "#BF7F3F"}, - {"value": 3, "hex": "#C8C8C8"}, - {"value": "nv", "hex": "#FFFFFF"}, - {"value": "default", "hex": "#FFFFFF"}, + {"value": 1, "color": "#00BFBF"}, + {"value": 1.4, "color": "#00FF00"}, + {"value": 1.8, "color": "#FFFF00"}, + {"value": 2.2, "color": "#FF7F00"}, + {"value": 2.6, "color": "#BF7F3F"}, + {"value": 3, "color": "#C8C8C8"}, + {"value": "nv", "color": "#FFFFFF"}, + {"value": "default", "color": "#FFFFFF"}, ] assert expected == data, f"test failed: expected {expected} but got {data}" @@ -91,14 +91,14 @@ def test_r_colors_out_json_with_triplet_option(raster_color_dataset): ) validate_common_json_structure(data) expected = [ - {"value": 1, "triplet": "0:191:191"}, - {"value": 1.4, "triplet": "0:255:0"}, - {"value": 1.8, "triplet": "255:255:0"}, - {"value": 2.2, "triplet": "255:127:0"}, - {"value": 2.6, "triplet": "191:127:63"}, - {"value": 3, "triplet": "200:200:200"}, - {"value": "nv", "triplet": "255:255:255"}, - {"value": "default", "triplet": "255:255:255"}, + {"value": 1, "color": "0:191:191"}, + {"value": 1.4, "color": "0:255:0"}, + {"value": 1.8, "color": "255:255:0"}, + {"value": 2.2, "color": "255:127:0"}, + {"value": 2.6, "color": "191:127:63"}, + {"value": 3, "color": "200:200:200"}, + {"value": "nv", "color": "255:255:255"}, + {"value": "default", "color": "255:255:255"}, ] assert expected == data, f"test failed: expected {expected} but got {data}" @@ -115,14 +115,14 @@ def test_r_colors_out_json_with_rgb_option(raster_color_dataset): ) validate_common_json_structure(data) expected = [ - {"value": 1, "rgb": "rgb(0, 191, 191)"}, - {"value": 1.4, "rgb": "rgb(0, 255, 0)"}, - {"value": 1.8, "rgb": "rgb(255, 255, 0)"}, - {"value": 2.2, "rgb": "rgb(255, 127, 0)"}, - {"value": 2.6, "rgb": "rgb(191, 127, 63)"}, - {"value": 3, "rgb": "rgb(200, 200, 200)"}, - {"value": "nv", "rgb": "rgb(255, 255, 255)"}, - {"value": "default", "rgb": "rgb(255, 255, 255)"}, + {"value": 1, "color": "rgb(0, 191, 191)"}, + {"value": 1.4, "color": "rgb(0, 255, 0)"}, + {"value": 1.8, "color": "rgb(255, 255, 0)"}, + {"value": 2.2, "color": "rgb(255, 127, 0)"}, + {"value": 2.6, "color": "rgb(191, 127, 63)"}, + {"value": 3, "color": "rgb(200, 200, 200)"}, + {"value": "nv", "color": "rgb(255, 255, 255)"}, + {"value": "default", "color": "rgb(255, 255, 255)"}, ] assert expected == data, f"test failed: expected {expected} but got {data}" @@ -139,14 +139,14 @@ def test_r_colors_out_json_with_hex_option(raster_color_dataset): ) validate_common_json_structure(data) expected = [ - {"value": 1, "hex": "#00BFBF"}, - {"value": 1.4, "hex": "#00FF00"}, - {"value": 1.8, "hex": "#FFFF00"}, - {"value": 2.2, "hex": "#FF7F00"}, - {"value": 2.6, "hex": "#BF7F3F"}, - {"value": 3, "hex": "#C8C8C8"}, - {"value": "nv", "hex": "#FFFFFF"}, - {"value": "default", "hex": "#FFFFFF"}, + {"value": 1, "color": "#00BFBF"}, + {"value": 1.4, "color": "#00FF00"}, + {"value": 1.8, "color": "#FFFF00"}, + {"value": 2.2, "color": "#FF7F00"}, + {"value": 2.6, "color": "#BF7F3F"}, + {"value": 3, "color": "#C8C8C8"}, + {"value": "nv", "color": "#FFFFFF"}, + {"value": "default", "color": "#FFFFFF"}, ] assert expected == data, f"test failed: expected {expected} but got {data}" @@ -163,13 +163,13 @@ def test_r_colors_out_json_with_hsv_option(raster_color_dataset): ) validate_common_json_structure(data) expected = [ - {"value": 1, "hsv": "hsv(180, 100, 74)"}, - {"value": 1.4, "hsv": "hsv(120, 100, 100)"}, - {"value": 1.8, "hsv": "hsv(60, 100, 100)"}, - {"value": 2.2, "hsv": "hsv(29, 100, 100)"}, - {"value": 2.6, "hsv": "hsv(30, 67, 74)"}, - {"value": 3, "hsv": "hsv(0, 0, 78)"}, - {"value": "nv", "hsv": "hsv(0, 0, 100)"}, - {"value": "default", "hsv": "hsv(0, 0, 100)"}, + {"value": 1, "color": "hsv(180, 100, 74)"}, + {"value": 1.4, "color": "hsv(120, 100, 100)"}, + {"value": 1.8, "color": "hsv(60, 100, 100)"}, + {"value": 2.2, "color": "hsv(29, 100, 100)"}, + {"value": 2.6, "color": "hsv(30, 67, 74)"}, + {"value": 3, "color": "hsv(0, 0, 78)"}, + {"value": "nv", "color": "hsv(0, 0, 100)"}, + {"value": "default", "color": "hsv(0, 0, 100)"}, ] assert expected == data, f"test failed: expected {expected} but got {data}" diff --git a/vector/v.colors.out/main.c b/vector/v.colors.out/main.c index 8ea03b06ce5..5d5f84bebf0 100644 --- a/vector/v.colors.out/main.c +++ b/vector/v.colors.out/main.c @@ -28,7 +28,7 @@ int main(int argc, char **argv) { struct GModule *module; struct { - struct Option *map, *field, *file, *col; + struct Option *map, *field, *file, *col, *format, *color_format; } opt; struct { struct Flag *p; @@ -40,6 +40,8 @@ int main(int argc, char **argv) const char *file, *name, *layer, *column; FILE *fp; + ColorFormat clr_frmt; + G_gisinit(argv[0]); module = G_define_module(); @@ -65,6 +67,12 @@ int main(int argc, char **argv) opt.col->description = _("If not given, color rules refer to categories"); opt.col->guisection = _("Settings"); + opt.format = G_define_standard_option(G_OPT_F_FORMAT); + opt.format->guisection = _("Print"); + + opt.color_format = G_define_standard_option(G_OPT_C_FORMAT); + opt.color_format->guisection = _("Color"); + flag.p = G_define_flag(); flag.p->key = 'p'; flag.p->description = _("Output values as percentages"); @@ -106,8 +114,26 @@ int main(int argc, char **argv) else colors = &cat_colors; - Rast_print_colors(colors, (DCELL)min, (DCELL)max, fp, - flag.p->answer ? 1 : 0); + if (strcmp(opt.format->answer, "json") == 0) { + if (strcmp(opt.color_format->answer, "rgb") == 0) { + clr_frmt = RGB; + } + else if (strcmp(opt.color_format->answer, "triplet") == 0) { + clr_frmt = TRIPLET; + } + else if (strcmp(opt.color_format->answer, "hsv") == 0) { + clr_frmt = HSV; + } + else { + clr_frmt = HEX; + } + Rast_print_json_colors(colors, (DCELL)min, (DCELL)max, fp, + flag.p->answer ? 1 : 0, clr_frmt); + } + else { + Rast_print_colors(colors, (DCELL)min, (DCELL)max, fp, + flag.p->answer ? 1 : 0); + } exit(EXIT_SUCCESS); } diff --git a/vector/v.colors.out/tests/conftest.py b/vector/v.colors.out/tests/conftest.py new file mode 100644 index 00000000000..120b37b6e60 --- /dev/null +++ b/vector/v.colors.out/tests/conftest.py @@ -0,0 +1,27 @@ +"""Fixture for v.colors.out test""" + +import os +import pytest +import grass.script as gs + + +@pytest.fixture +def vector_color_dataset(tmp_path): + """Set up a GRASS session and create test vector with color rules.""" + project = tmp_path / "vector_color_project" + gs.create_project(project) + with gs.setup.init(project, env=os.environ.copy()) as session: + gs.run_command( + "g.region", + n=90, + s=-90, + e=180, + w=-180, + res=10, + env=session.env, + ) + gs.run_command( + "v.mkgrid", map="a", grid=[10, 10], type="point", env=session.env + ) + gs.run_command("v.colors", map="a", color="elevation", env=session.env) + yield session diff --git a/vector/v.colors.out/tests/v_colors_out_test.py b/vector/v.colors.out/tests/v_colors_out_test.py new file mode 100644 index 00000000000..c8156e7e627 --- /dev/null +++ b/vector/v.colors.out/tests/v_colors_out_test.py @@ -0,0 +1,175 @@ +"""Tests of v.colors.out""" + +import grass.script as gs + + +def validate_plain_text_output(data): + """Validate the structure and content of the plain text output.""" + assert data + assert len(data) == 8, "The output does not match the expected number of items (8)." + expected = { + "1 0:191:191", + "20.8 0:255:0", + "40.6 255:255:0", + "60.4 255:127:0", + "80.2 191:127:63", + "100 200:200:200", + "nv 255:255:255", + "default 255:255:255", + } + assert ( + expected == data.keys() + ), f"test failed: expected {expected} but got {data.keys()}" + + +def test_v_colors_out_plain_output(vector_color_dataset): + """Test v.colors.out command for plain output format.""" + session = vector_color_dataset + data = gs.parse_command("v.colors.out", map="a", format="plain", env=session.env) + validate_plain_text_output(data) + + +def test_v_colors_out_without_format_option(vector_color_dataset): + """Test v.colors.out command without any format option.""" + session = vector_color_dataset + data = gs.parse_command("v.colors.out", map="a", env=session.env) + validate_plain_text_output(data) + + +def test_v_colors_out_with_p_flag(vector_color_dataset): + """Test v.colors.out command with percentage values.""" + session = vector_color_dataset + data = gs.parse_command("v.colors.out", map="a", flags="p", env=session.env) + assert data + assert len(data) == 8, "The output does not match the expected number of items (8)." + expected = { + "0% 0:191:191", + "20% 0:255:0", + "40% 255:255:0", + "60% 255:127:0", + "80% 191:127:63", + "100% 200:200:200", + "nv 255:255:255", + "default 255:255:255", + } + assert ( + expected == data.keys() + ), f"test failed: expected {expected} but got {data.keys()}" + + +def validate_common_json_structure(data): + """Validate the common structure and content of the JSON output.""" + assert isinstance(data, list), "Output data should be a list of entries." + assert ( + len(data) == 8 + ), "The length of the output JSON does not match the expected value of 8." + + +def test_v_colors_out_json_with_default_option(vector_color_dataset): + """Test v.colors.out command for JSON output format for default color option.""" + session = vector_color_dataset + data = gs.parse_command("v.colors.out", map="a", format="json", env=session.env) + validate_common_json_structure(data) + expected = [ + {"value": 1, "color": "#00BFBF"}, + {"value": 20.8, "color": "#00FF00"}, + {"value": 40.6, "color": "#FFFF00"}, + {"value": 60.4, "color": "#FF7F00"}, + {"value": 80.2, "color": "#BF7F3F"}, + {"value": 100, "color": "#C8C8C8"}, + {"value": "nv", "color": "#FFFFFF"}, + {"value": "default", "color": "#FFFFFF"}, + ] + assert expected == data, f"test failed: expected {expected} but got {data}" + + +def test_v_colors_out_json_with_triplet_option(vector_color_dataset): + """Test v.colors.out command for JSON output format for triplet color option.""" + session = vector_color_dataset + data = gs.parse_command( + "v.colors.out", map="a", format="json", color_format="triplet", env=session.env + ) + validate_common_json_structure(data) + expected = [ + {"value": 1, "color": "0:191:191"}, + {"value": 20.8, "color": "0:255:0"}, + {"value": 40.6, "color": "255:255:0"}, + {"value": 60.4, "color": "255:127:0"}, + {"value": 80.2, "color": "191:127:63"}, + {"value": 100, "color": "200:200:200"}, + {"value": "nv", "color": "255:255:255"}, + {"value": "default", "color": "255:255:255"}, + ] + assert expected == data, f"test failed: expected {expected} but got {data}" + + +def test_v_colors_out_json_with_rgb_option(vector_color_dataset): + """Test v.colors.out command for JSON output format for rgb color option.""" + session = vector_color_dataset + data = gs.parse_command( + "v.colors.out", + map="a", + format="json", + color_format="rgb", + env=session.env, + ) + validate_common_json_structure(data) + expected = [ + {"value": 1, "color": "rgb(0, 191, 191)"}, + {"value": 20.8, "color": "rgb(0, 255, 0)"}, + {"value": 40.6, "color": "rgb(255, 255, 0)"}, + {"value": 60.4, "color": "rgb(255, 127, 0)"}, + {"value": 80.2, "color": "rgb(191, 127, 63)"}, + {"value": 100, "color": "rgb(200, 200, 200)"}, + {"value": "nv", "color": "rgb(255, 255, 255)"}, + {"value": "default", "color": "rgb(255, 255, 255)"}, + ] + assert expected == data, f"test failed: expected {expected} but got {data}" + + +def test_v_colors_out_json_with_hex_option(vector_color_dataset): + """Test v.colors.out command for JSON output format for hex color option.""" + session = vector_color_dataset + data = gs.parse_command( + "v.colors.out", + map="a", + format="json", + color_format="hex", + env=session.env, + ) + validate_common_json_structure(data) + expected = [ + {"value": 1, "color": "#00BFBF"}, + {"value": 20.8, "color": "#00FF00"}, + {"value": 40.6, "color": "#FFFF00"}, + {"value": 60.4, "color": "#FF7F00"}, + {"value": 80.2, "color": "#BF7F3F"}, + {"value": 100, "color": "#C8C8C8"}, + {"value": "nv", "color": "#FFFFFF"}, + {"value": "default", "color": "#FFFFFF"}, + ] + assert expected == data, f"test failed: expected {expected} but got {data}" + + +def test_v_colors_out_json_with_hsv_option(vector_color_dataset): + """Test v.colors.out command for JSON output format for hsv color option.""" + session = vector_color_dataset + data = gs.parse_command( + "v.colors.out", + map="a", + format="json", + color_format="hsv", + env=session.env, + ) + validate_common_json_structure(data) + expected = [ + {"value": 1, "color": "hsv(180, 100, 74)"}, + {"value": 20.8, "color": "hsv(120, 100, 100)"}, + {"value": 40.6, "color": "hsv(60, 100, 100)"}, + {"value": 60.4, "color": "hsv(29, 100, 100)"}, + {"value": 80.2, "color": "hsv(30, 67, 74)"}, + {"value": 100, "color": "hsv(0, 0, 78)"}, + {"value": "nv", "color": "hsv(0, 0, 100)"}, + {"value": "default", "color": "hsv(0, 0, 100)"}, + ] + assert expected == data, f"test failed: expected {expected} but got {data}"