Skip to content

Commit 3326346

Browse files
committed
add cast tests, and allow cast of float to integer
1 parent 1def663 commit 3326346

4 files changed

Lines changed: 237 additions & 2 deletions

File tree

src/bin/unit_test_attribute.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,6 +1369,49 @@ static size_t command_calc_nary(command_result_t *result, command_file_ctx_t *cc
13691369
RETURN_OK(slen);
13701370
}
13711371

1372+
/** Perform casting
1373+
*
1374+
*/
1375+
static size_t command_cast(command_result_t *result, command_file_ctx_t *cc,
1376+
char *data, UNUSED size_t data_used, char *in, size_t inlen)
1377+
{
1378+
fr_value_box_t *a, *out;
1379+
size_t match_len;
1380+
fr_type_t type;
1381+
char const *p, *value, *end;
1382+
size_t slen;
1383+
1384+
a = talloc_zero(cc->tmp_ctx, fr_value_box_t);
1385+
1386+
p = in;
1387+
end = in + inlen;
1388+
1389+
match_len = parse_typed_value(result, a, &value, p, end - p);
1390+
if (match_len == 0) return 0; /* errors have already been updated */
1391+
1392+
p += match_len;
1393+
fr_skip_whitespace(p);
1394+
1395+
out = talloc_zero(cc->tmp_ctx, fr_value_box_t);
1396+
1397+
if (strncmp(p, "->", 2) != 0) RETURN_PARSE_ERROR(0);
1398+
p += 2;
1399+
fr_skip_whitespace(p);
1400+
1401+
type = fr_table_value_by_longest_prefix(&match_len, fr_type_table, p, end - p, FR_TYPE_MAX);
1402+
if (type == FR_TYPE_MAX) RETURN_PARSE_ERROR(0);
1403+
fr_value_box_init(out, type, NULL, false);
1404+
1405+
if (fr_value_box_cast(out, out, type, NULL, a) < 0) {
1406+
RETURN_OK_WITH_ERROR();
1407+
}
1408+
1409+
slen = fr_value_box_print(&FR_SBUFF_OUT(data, COMMAND_OUTPUT_MAX), out, NULL);
1410+
if (slen <= 0) RETURN_OK_WITH_ERROR();
1411+
1412+
RETURN_OK(slen);
1413+
}
1414+
13721415
/** Change the working directory
13731416
*
13741417
*/
@@ -3042,6 +3085,11 @@ static fr_table_ptr_sorted_t commands[] = {
30423085
.usage = "calc_nary op <type1> <value1> <type2> <value2> ... -> <output-type>",
30433086
.description = "Perform calculations on value boxes",
30443087
}},
3088+
{ L("cast "), &(command_entry_t){
3089+
.func = command_cast,
3090+
.usage = "cast (type) <value> -> <output-type>",
3091+
.description = "Perform calculations on value boxes",
3092+
}},
30453093
{ L("cd "), &(command_entry_t){
30463094
.func = command_cd,
30473095
.usage = "cd <path>",

src/lib/util/value.c

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3224,6 +3224,161 @@ static inline int fr_value_box_cast_to_integer(TALLOC_CTX *ctx, fr_value_box_t *
32243224
return 0;
32253225
}
32263226

3227+
case FR_TYPE_FLOAT32:
3228+
if (src->vb_float32 < (double) fr_value_box_integer_min[dst_type]) {
3229+
underflow:
3230+
fr_strerror_const("Source value for cast would underflow destination type");
3231+
return -1;
3232+
}
3233+
3234+
if (src->vb_float32 > (double) fr_value_box_integer_max[dst_type]) {
3235+
overflow:
3236+
fr_strerror_const("Source value for cast would overflow destination type");
3237+
return -1;
3238+
}
3239+
3240+
switch (dst_type) {
3241+
case FR_TYPE_UINT8:
3242+
dst->vb_uint8 = src->vb_float32;
3243+
break;
3244+
3245+
case FR_TYPE_UINT16:
3246+
dst->vb_uint16 = src->vb_float32;
3247+
break;
3248+
3249+
case FR_TYPE_UINT32:
3250+
dst->vb_uint32 = src->vb_float32;
3251+
break;
3252+
3253+
case FR_TYPE_UINT64:
3254+
dst->vb_uint64 = src->vb_float32;
3255+
break;
3256+
3257+
case FR_TYPE_INT8:
3258+
dst->vb_int8 = src->vb_float32;
3259+
break;
3260+
3261+
case FR_TYPE_INT16:
3262+
dst->vb_int16 = src->vb_float32;
3263+
break;
3264+
3265+
case FR_TYPE_INT32:
3266+
dst->vb_int32 = src->vb_float32;
3267+
break;
3268+
3269+
case FR_TYPE_INT64:
3270+
dst->vb_int64 = src->vb_float32;
3271+
break;
3272+
3273+
case FR_TYPE_SIZE:
3274+
dst->vb_size = src->vb_float32;
3275+
break;
3276+
3277+
case FR_TYPE_DATE: {
3278+
int64_t sec, nsec;
3279+
3280+
sec = src->vb_float32;
3281+
sec *= NSEC;
3282+
nsec = ((src->vb_float32 * NSEC) - ((float) sec));
3283+
3284+
dst->vb_date = fr_unix_time_from_nsec(sec + nsec);
3285+
}
3286+
break;
3287+
3288+
case FR_TYPE_TIME_DELTA: {
3289+
int64_t sec, nsec;
3290+
3291+
sec = src->vb_float32;
3292+
sec *= NSEC;
3293+
nsec = ((src->vb_float32 * NSEC) - ((float) sec));
3294+
3295+
dst->vb_time_delta = fr_time_delta_from_nsec(sec + nsec);
3296+
}
3297+
break;
3298+
3299+
default:
3300+
goto bad_cast;
3301+
}
3302+
return 0;
3303+
3304+
case FR_TYPE_FLOAT64:
3305+
if (src->vb_float64 < (double) fr_value_box_integer_min[dst_type]) goto underflow;
3306+
3307+
if (src->vb_float64 > (double) fr_value_box_integer_max[dst_type]) goto overflow;
3308+
3309+
switch (dst_type) {
3310+
case FR_TYPE_UINT8:
3311+
dst->vb_uint8 = src->vb_float64;
3312+
break;
3313+
3314+
case FR_TYPE_UINT16:
3315+
dst->vb_uint16 = src->vb_float64;
3316+
break;
3317+
3318+
case FR_TYPE_UINT32:
3319+
dst->vb_uint32 = src->vb_float64;
3320+
break;
3321+
3322+
case FR_TYPE_UINT64:
3323+
dst->vb_uint64 = src->vb_float64;
3324+
break;
3325+
3326+
case FR_TYPE_INT8:
3327+
dst->vb_int8 = src->vb_float64;
3328+
break;
3329+
3330+
case FR_TYPE_INT16:
3331+
dst->vb_int16 = src->vb_float64;
3332+
break;
3333+
3334+
case FR_TYPE_INT32:
3335+
dst->vb_int32 = src->vb_float64;
3336+
break;
3337+
3338+
case FR_TYPE_INT64:
3339+
dst->vb_int64 = src->vb_float64;
3340+
break;
3341+
3342+
case FR_TYPE_SIZE:
3343+
dst->vb_size = src->vb_float64;
3344+
break;
3345+
3346+
case FR_TYPE_DATE: {
3347+
int64_t sec, nsec;
3348+
3349+
sec = src->vb_float64;
3350+
sec *= NSEC;
3351+
nsec = ((src->vb_float64 * NSEC) - ((double) sec));
3352+
3353+
/*
3354+
* @todo - respect time res
3355+
*/
3356+
dst->vb_date = fr_unix_time_from_nsec(sec + nsec);
3357+
}
3358+
break;
3359+
3360+
case FR_TYPE_TIME_DELTA: {
3361+
int64_t sec, nsec;
3362+
int64_t res = NSEC;
3363+
bool fail = false;
3364+
3365+
if (dst->enumv) res = fr_time_multiplier_by_res[dst->enumv->flags.flag_time_res];
3366+
3367+
sec = src->vb_float64;
3368+
sec *= res;
3369+
nsec = ((src->vb_float64 * res) - ((double) sec));
3370+
3371+
dst->vb_time_delta = fr_time_delta_from_integer(&fail, sec + nsec,
3372+
dst->enumv ? dst->enumv->flags.flag_time_res : FR_TIME_RES_NSEC);
3373+
if (fail) goto overflow;
3374+
}
3375+
break;
3376+
3377+
default:
3378+
goto bad_cast;
3379+
}
3380+
return 0;
3381+
32273382
default:
32283383
break;
32293384
}

src/tests/modules/all.mk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ $(OUTPUT)/%: $(DIR)/%.unlang $(TEST_BIN_DIR)/unit_test_module | build.raddb
103103
@echo "MODULE-TEST $(TEST)"
104104
${Q}mkdir -p $(dir $@)
105105
${Q}cp $(if $(wildcard $(basename $<).attrs),$(basename $<).attrs,src/tests/modules/default-input.attrs) $@.attrs
106-
${Q}if ! MODULE_TEST_DIR=$(dir $<) MODULE_TEST_UNLANG=$< TEST="$(TEST)" $(TEST_BIN)/unit_test_module -D share/dictionary -d src/tests/modules/ -i "$@.attrs" -f "$@.attrs" -r "$@" -S xlat_func_bare_words=yes -xxx > "$@.log" 2>&1 || ! test -f "$@"; then \
106+
${Q}if ! MODULE_TEST_DIR=$(dir $<) MODULE_TEST_UNLANG=$< TEST="$(TEST)" $(TEST_BIN)/unit_test_module -D share/dictionary -d src/tests/modules/ -i "$@.attrs" -f "$@.attrs" -r "$@" -S xlat_func_bare_words=no -xxx > "$@.log" 2>&1 || ! test -f "$@"; then \
107107
if ! grep ERROR $< 2>&1 > /dev/null; then \
108108
if grep 'LeakSanitizer has encountered a fatal error' $@.log 2>&1 > /dev/null; then \
109109
echo "MODULE-TEST $(TEST) - ignoring LeakSanitizer fatal error."; \
@@ -119,7 +119,7 @@ $(OUTPUT)/%: $(DIR)/%.unlang $(TEST_BIN_DIR)/unit_test_module | build.raddb
119119
if [ "$$EXPECTED" != "$$FOUND" ]; then \
120120
cat "$@.log"; \
121121
echo "# $@.log"; \
122-
echo "MODULE_TEST_DIR=$(dir $<) MODULE_TEST_UNLANG=$< $(TEST_BIN)/unit_test_module -D share/dictionary -d src/tests/modules/ -i \"$@.attrs\" -f \"$@.attrs\" -r \"$@\" -S xlat_func_bare_words=yes -xx"; \
122+
echo "MODULE_TEST_DIR=$(dir $<) MODULE_TEST_UNLANG=$< $(TEST_BIN)/unit_test_module -D share/dictionary -d src/tests/modules/ -i \"$@.attrs\" -f \"$@.attrs\" -r \"$@\" -S xlat_func_bare_words=no -xx"; \
123123
exit 1; \
124124
else \
125125
touch "$@"; \

src/tests/unit/cast.txt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
cast ipaddr 127.0.0.1 -> uint32
2+
match 2130706433
3+
4+
cast ipaddr 127.0.0.1 -> octets
5+
match 0x7f000001
6+
7+
cast float64 0.5 -> time_delta
8+
match 0.5
9+
10+
cast float64 -0.5 -> time_delta
11+
match -0.5
12+
13+
cast float64 6.25 -> time_delta
14+
match 6.25
15+
16+
cast float64 1024 -> uint8
17+
match Source value for cast would overflow destination type
18+
19+
#
20+
# Input can be qualified with a resolution. Output is seconds by default.
21+
#
22+
cast time_delta 6.25s -> time_delta
23+
match 6.25
24+
25+
cast time_delta 6.25ms -> time_delta
26+
match 0.00625
27+
28+
cast time_delta 6.25us -> time_delta
29+
match 0.00000625
30+
31+
count
32+
match 18

0 commit comments

Comments
 (0)