mirror of
https://github.com/google/pebble.git
synced 2025-05-21 02:45:00 +00:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
753
tests/fw/applib/test_template_string.c
Normal file
753
tests/fw/applib/test_template_string.c
Normal file
|
@ -0,0 +1,753 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "clar.h"
|
||||
|
||||
#include "applib/template_string.h"
|
||||
#include "applib/template_string_private.h"
|
||||
|
||||
#include "util/size.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#define DEBUG_PRINTING 1
|
||||
#if DEBUG_PRINTING
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
|
||||
void prv_template_evaluate_filter(TemplateStringState *state, const char *filter_name,
|
||||
const char *params);
|
||||
|
||||
static const char *s_error_strings[] = {
|
||||
"Success.",
|
||||
"Can't resolve.",
|
||||
"Missing closing brace.",
|
||||
"Missing argument.",
|
||||
"No result generated.",
|
||||
"Unknown filter.",
|
||||
"format() was not last filter.",
|
||||
"Time unit in predicate is invalid.",
|
||||
"Escape character at end of string.",
|
||||
"Opening parenthesis for filter was missing.",
|
||||
"Closing parenthesis for filter was missing.",
|
||||
"Invalid conversion specifier for format.",
|
||||
"Invalid parameter.",
|
||||
"Opening quote for filter was missing.",
|
||||
"Closing quote for filter was missing.",
|
||||
"Invalid argument separator.",
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Fakes & Stubs
|
||||
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_i18n.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Test setup
|
||||
|
||||
#define EVAL_FALL_THROUGH -1337
|
||||
#define EVAL_DEFAULT 0
|
||||
|
||||
static TemplateStringState s_state;
|
||||
static char s_output[256];
|
||||
static TemplateStringVars s_vars;
|
||||
static TemplateStringError s_error;
|
||||
static TemplateStringEvalConditions s_cond;
|
||||
|
||||
static void prv_state_init(void) {
|
||||
s_state = (TemplateStringState){
|
||||
.output = s_output,
|
||||
.output_remaining = sizeof(s_output),
|
||||
.vars = &s_vars,
|
||||
.error = &s_error,
|
||||
.eval_cond = &s_cond,
|
||||
|
||||
.time_was_until = false,
|
||||
.filter_state = 0,
|
||||
.filters_complete = false,
|
||||
};
|
||||
memset(s_output, 'Z', sizeof(s_output));
|
||||
memset(&s_vars, 0, sizeof(s_vars));
|
||||
memset(&s_error, 0, sizeof(s_error));
|
||||
memset(&s_cond, 0, sizeof(s_cond));
|
||||
s_cond.eval_time = INT_MAX;
|
||||
}
|
||||
|
||||
void test_template_string__initialize(void) {
|
||||
}
|
||||
|
||||
void test_template_string__cleanup(void) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Test truncation
|
||||
|
||||
static const struct {
|
||||
size_t size;
|
||||
time_t intime;
|
||||
const char *instr;
|
||||
const char *output;
|
||||
} s_truncation_tests[] = {
|
||||
{ .size = 1, .intime = 1000,
|
||||
.instr = "foo",
|
||||
.output = "",
|
||||
},
|
||||
{ .size = 3, .intime = 1000,
|
||||
.instr = "foo",
|
||||
.output = "fo",
|
||||
},
|
||||
{ .size = 3, .intime = 1000,
|
||||
.instr = "{format('foo')}",
|
||||
.output = "fo",
|
||||
},
|
||||
{ .size = 1, .intime = 1000,
|
||||
.instr = "{time_until(1004)|format('%S')}",
|
||||
.output = "",
|
||||
},
|
||||
{ .size = 2, .intime = 1000,
|
||||
.instr = "{time_until(1040)|format('%S')}",
|
||||
.output = "4",
|
||||
},
|
||||
{ .size = 6, .intime = 1000,
|
||||
.instr = "{time_until(1040)|format('%uS')}",
|
||||
.output = "40 se",
|
||||
},
|
||||
};
|
||||
|
||||
void test_template_string__truncation(void) {
|
||||
for(size_t i = 0; i < ARRAY_LENGTH(s_truncation_tests); i++) {
|
||||
#if DEBUG_PRINTING
|
||||
printf("size: %zu\n", s_truncation_tests[i].size);
|
||||
printf("intime: %jd\n", s_truncation_tests[i].intime);
|
||||
printf("input: \"%s\"\n", s_truncation_tests[i].instr);
|
||||
printf("result: \"%s\"\n", s_truncation_tests[i].output);
|
||||
#endif
|
||||
|
||||
TemplateStringVars vars = {};
|
||||
TemplateStringError err = {};
|
||||
TemplateStringEvalConditions cond = {};
|
||||
|
||||
vars.current_time = s_truncation_tests[i].intime;
|
||||
cond.eval_time = EVAL_FALL_THROUGH;
|
||||
|
||||
memset(s_output, 'Z', sizeof(s_output));
|
||||
template_string_evaluate(s_truncation_tests[i].instr, s_output, s_truncation_tests[i].size,
|
||||
&cond, &vars, &err);
|
||||
|
||||
cl_assert_equal_s(s_output, s_truncation_tests[i].output);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Test NULL arguments
|
||||
|
||||
void test_template_string__null_arguments(void) {
|
||||
{
|
||||
TemplateStringVars vars = {};
|
||||
TemplateStringError err = {};
|
||||
TemplateStringEvalConditions cond = {};
|
||||
vars.current_time = 0;
|
||||
|
||||
cond.eval_time = EVAL_FALL_THROUGH;
|
||||
cond.force_eval_on_time = true;
|
||||
memset(s_output, 'Z', sizeof(s_output));
|
||||
bool ret = template_string_evaluate("test string {time_until(5)|format('%uS')}", s_output,
|
||||
sizeof(s_output), &cond, &vars, &err);
|
||||
cl_assert_equal_b(ret, true);
|
||||
cl_assert_equal_s(s_output, "test string 5 seconds");
|
||||
cl_assert_equal_i(cond.eval_time, 1);
|
||||
cl_assert_equal_b(cond.force_eval_on_time, true);
|
||||
}
|
||||
|
||||
{
|
||||
TemplateStringVars vars = {};
|
||||
TemplateStringError err = {};
|
||||
TemplateStringEvalConditions cond = {};
|
||||
vars.current_time = 0;
|
||||
|
||||
cond.eval_time = EVAL_FALL_THROUGH;
|
||||
cond.force_eval_on_time = true;
|
||||
strcpy(s_output, "hurf");
|
||||
bool ret = template_string_evaluate("test string {time_until(5)|format('%uS')}", s_output, 0,
|
||||
&cond, &vars, &err);
|
||||
cl_assert_equal_b(ret, true);
|
||||
cl_assert_equal_s(s_output, "hurf");
|
||||
cl_assert_equal_i(cond.eval_time, 1);
|
||||
cl_assert_equal_b(cond.force_eval_on_time, true);
|
||||
}
|
||||
|
||||
{
|
||||
TemplateStringVars vars = {};
|
||||
TemplateStringError err = {};
|
||||
TemplateStringEvalConditions cond = {};
|
||||
vars.current_time = 0;
|
||||
|
||||
cond.eval_time = EVAL_FALL_THROUGH;
|
||||
cond.force_eval_on_time = true;
|
||||
strcpy(s_output, "hurf");
|
||||
bool ret = template_string_evaluate("test string {time_until(5)|format('%uS')}", NULL,
|
||||
sizeof(s_output), &cond, &vars, &err);
|
||||
cl_assert_equal_b(ret, true);
|
||||
cl_assert_equal_s(s_output, "hurf");
|
||||
cl_assert_equal_i(cond.eval_time, 1);
|
||||
cl_assert_equal_b(cond.force_eval_on_time, true);
|
||||
}
|
||||
|
||||
{
|
||||
TemplateStringVars vars = {};
|
||||
TemplateStringError err = {};
|
||||
vars.current_time = 0;
|
||||
|
||||
memset(s_output, 'Z', sizeof(s_output));
|
||||
bool ret = template_string_evaluate("test string {time_until(5)|format('%uS')}", s_output,
|
||||
sizeof(s_output), NULL, &vars, &err);
|
||||
cl_assert_equal_b(ret, true);
|
||||
cl_assert_equal_s(s_output, "test string 5 seconds");
|
||||
}
|
||||
|
||||
{
|
||||
TemplateStringVars vars = {};
|
||||
TemplateStringError err = {};
|
||||
vars.current_time = 0;
|
||||
|
||||
bool ret = template_string_evaluate("test string {time_until(5)|format('%uS',)}", NULL, 0,
|
||||
NULL, &vars, &err);
|
||||
cl_assert_equal_b(ret, false);
|
||||
cl_assert_equal_i(err.status, TemplateStringErrorStatus_MissingArgument);
|
||||
cl_assert_equal_i(err.index_in_string, 40);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Test `time_since` and `time_until` filters
|
||||
|
||||
static const struct {
|
||||
time_t current_time;
|
||||
const char *params;
|
||||
intmax_t done_state;
|
||||
} s_time_since_tests[] = {
|
||||
{ .current_time = 1234567,
|
||||
.params = "1234567)",
|
||||
.done_state = 0,
|
||||
},
|
||||
{ .current_time = 1234567,
|
||||
.params = "1234560)",
|
||||
.done_state = 7,
|
||||
},
|
||||
{ .current_time = 1234567,
|
||||
.params = "1234570)",
|
||||
.done_state = -3,
|
||||
},
|
||||
{ .current_time = 234567,
|
||||
.params = "1234567)",
|
||||
.done_state = -1000000,
|
||||
},
|
||||
};
|
||||
|
||||
void test_template_string__time_since_until(void) {
|
||||
for(size_t i = 0; i < ARRAY_LENGTH(s_time_since_tests); i++) {
|
||||
#if DEBUG_PRINTING
|
||||
printf("current_time: %ld\n", s_time_since_tests[i].current_time);
|
||||
printf("parameter: \"%s\"\n", s_time_since_tests[i].params);
|
||||
printf("result: %jd\n", s_time_since_tests[i].done_state);
|
||||
#endif
|
||||
|
||||
prv_state_init();
|
||||
s_vars.current_time = s_time_since_tests[i].current_time;
|
||||
prv_template_evaluate_filter(&s_state, "time_since", s_time_since_tests[i].params);
|
||||
cl_assert_equal_b(s_state.filters_complete, false);
|
||||
cl_assert_equal_i(s_state.filter_state, s_time_since_tests[i].done_state);
|
||||
|
||||
prv_state_init();
|
||||
s_vars.current_time = s_time_since_tests[i].current_time;
|
||||
prv_template_evaluate_filter(&s_state, "time_until", s_time_since_tests[i].params);
|
||||
cl_assert_equal_b(s_state.filters_complete, false);
|
||||
cl_assert_equal_i(s_state.filter_state, -s_time_since_tests[i].done_state);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Test `format` filter
|
||||
|
||||
typedef struct FormatTestData {
|
||||
const char *params;
|
||||
intmax_t filter_state;
|
||||
bool time_was_until;
|
||||
|
||||
const char *expect_str;
|
||||
time_t expect_eval_time;
|
||||
TemplateStringErrorStatus expect_status;
|
||||
size_t expect_index;
|
||||
} FormatTestData;
|
||||
|
||||
static const FormatTestData s_format_tests[] = {
|
||||
// Simple text tests
|
||||
{ "'doo')", 3600, true,
|
||||
"doo",
|
||||
INT_MAX,
|
||||
},
|
||||
|
||||
// Some error testing
|
||||
{ ">5H'%T')", 1, true,
|
||||
"",
|
||||
INT_MAX,
|
||||
TemplateStringErrorStatus_InvalidTimeUnit,
|
||||
3,
|
||||
},
|
||||
{ "'%T',)", 1, true,
|
||||
"1",
|
||||
1,
|
||||
TemplateStringErrorStatus_MissingArgument,
|
||||
5,
|
||||
},
|
||||
{ "'%T'fj)", 1, true,
|
||||
"1",
|
||||
1,
|
||||
TemplateStringErrorStatus_InvalidArgumentSeparator,
|
||||
4,
|
||||
},
|
||||
|
||||
// Basic %T tests
|
||||
{ "'%T')", 1, true,
|
||||
"1",
|
||||
1,
|
||||
},
|
||||
{ "'%T')", 60, true,
|
||||
"1:00",
|
||||
1,
|
||||
},
|
||||
{ "'%T')", 3600, true,
|
||||
"1:00:00",
|
||||
1,
|
||||
},
|
||||
{ "'%T')", -3666, true,
|
||||
"-1:01:06",
|
||||
1,
|
||||
},
|
||||
|
||||
// Basic %R tests
|
||||
{ "'%R')", 1, true,
|
||||
"0",
|
||||
2,
|
||||
},
|
||||
{ "'%R')", 66, true,
|
||||
"1",
|
||||
7,
|
||||
},
|
||||
{ "'%R')", 3607, true,
|
||||
"1:00",
|
||||
8,
|
||||
},
|
||||
{ "'%R')", -3666, true,
|
||||
"-1:01",
|
||||
7,
|
||||
},
|
||||
|
||||
// Advanced %T tests
|
||||
{ "'%0T')", 3666, true,
|
||||
"01:01:06",
|
||||
1,
|
||||
},
|
||||
{ "'%uT')", 3666, true,
|
||||
"1 hour, 1 minute, and 6 seconds",
|
||||
1,
|
||||
},
|
||||
{ "'%aT')", 3666, true,
|
||||
"1 hr 1 min 6 sec",
|
||||
1,
|
||||
},
|
||||
{ "'%auT')", 3666, true,
|
||||
"1 hour, 1 minute, and 6 seconds",
|
||||
1,
|
||||
},
|
||||
{ "'%0uT')", 3666, true,
|
||||
"01 hour, 01 minute, and 06 seconds",
|
||||
1,
|
||||
},
|
||||
{ "'%fT')", 129666, true,
|
||||
"36:01:06",
|
||||
1,
|
||||
},
|
||||
{ "'%T')", 129666, true,
|
||||
"12:01:06",
|
||||
1,
|
||||
},
|
||||
|
||||
// Advanced %R tests
|
||||
{ "'%0R')", 3666, true,
|
||||
"01:01",
|
||||
7,
|
||||
},
|
||||
{ "'%uR')", 3666, true,
|
||||
"1 hour, and 1 minute",
|
||||
7,
|
||||
},
|
||||
{ "'%aR')", 3666, true,
|
||||
"1 hr 1 min",
|
||||
7,
|
||||
},
|
||||
{ "'%auR')", 3666, true,
|
||||
"1 hour, and 1 minute",
|
||||
7,
|
||||
},
|
||||
{ "'%0uR')", 3666, true,
|
||||
"01 hour, and 01 minute",
|
||||
7,
|
||||
},
|
||||
{ "'%fR')", 129666, true,
|
||||
"36:01",
|
||||
7,
|
||||
},
|
||||
{ "'%R')", 129666, true,
|
||||
"12:01",
|
||||
7,
|
||||
},
|
||||
|
||||
// Predicate tests
|
||||
{ ">1d12H:'%0ud',<0S:'%-uS since',<60S:'%uS')", 9, true,
|
||||
"9 seconds",
|
||||
1,
|
||||
},
|
||||
{ ">1d12H:'%0ud',<0S:'%-uS since',<60S:'%0uS')", 129600, true,
|
||||
"",
|
||||
129601 - 60, // Time left until we hit <60S
|
||||
TemplateStringErrorStatus_CantResolve,
|
||||
42,
|
||||
},
|
||||
{ ">1d12H:'%0fud',<0S:'%-uS since',<60S:'%uS')", 129601, true,
|
||||
"01 day",
|
||||
1,
|
||||
},
|
||||
// 1d12H1S
|
||||
{ ">=1d14H:'%0fud',<1d13H:'%0fud',>1d12H:'%0fud')", 129601, true,
|
||||
"01 day",
|
||||
43202, // 12H2S (time=1d-1S)
|
||||
},
|
||||
// 1d12H
|
||||
{ ">=1d14H:'%0fud',<1d13H:'%0fud',>1d12H:'%0fud')", 129600, true,
|
||||
"01 day",
|
||||
43201, // 12H1S (time=1d-1S)
|
||||
},
|
||||
// 1d13H-100S
|
||||
{ ">=1d14H:'%0fud',<1d13H:'%0fud',>1d12H:'%0fud')", 133100, true,
|
||||
"01 day",
|
||||
46701, // 13H-99S (time=1d12H)
|
||||
},
|
||||
// 1d13H100S
|
||||
{ ">=1d14H:'%0fud',<1d13H:'%0fud',>1d12H:'%0fud')", 133300, true,
|
||||
"01 day",
|
||||
101, // time=1d13H-1S
|
||||
},
|
||||
// 1d14H100S
|
||||
{ ">=1d14H:'%0fud',<1d13H:'%0fud',>1d12H:'%0fud')", 136900, true,
|
||||
"01 day",
|
||||
101, // time=1d14H-1S
|
||||
},
|
||||
|
||||
// Predicate tests w/ since
|
||||
// 1d14H
|
||||
{ ">=1d14H:'%0fud',<1d13H:'%0fud',>1d12H:'%0fud')", 136800, false,
|
||||
"01 day",
|
||||
36000, // 2D
|
||||
},
|
||||
// 1d14H-100S
|
||||
{ ">=1d14H:'%0fud',<1d13H:'%0fud',>1d12H:'%0fud')", 136700, false,
|
||||
"01 day",
|
||||
100, // time=1d14H
|
||||
},
|
||||
// 1d13H
|
||||
{ ">=1d14H:'%0fud',<1d13H:'%0fud',>1d12H:'%0fud')", 133200, false,
|
||||
"01 day",
|
||||
3600, // 1H (time=1d14H)
|
||||
},
|
||||
// 1d13H-10S
|
||||
{ ">=1d14H:'%0fud',<1d13H:'%0fud',>1d12H:'%0fud')", 133190, false,
|
||||
"01 day",
|
||||
10, // 10S (time=1d13H)
|
||||
},
|
||||
// 1d12H
|
||||
{ ">=1d14H:'%0fud',<1d13H:'%0fud',>1d12H:'%0fud')", 129600, false,
|
||||
"01 day",
|
||||
1, // (time=1d12H1S)
|
||||
},
|
||||
};
|
||||
|
||||
void test_template_string__format(void) {
|
||||
for(size_t i = 0; i < ARRAY_LENGTH(s_format_tests); i++) {
|
||||
const FormatTestData *test = &s_format_tests[i];
|
||||
|
||||
prv_state_init();
|
||||
s_state.filter_state = test->filter_state;
|
||||
s_state.time_was_until = test->time_was_until;
|
||||
prv_template_evaluate_filter(&s_state, "format", test->params);
|
||||
|
||||
// The filter isn't required to NUL-terminate, so we gotta do it manually sometimes.
|
||||
if (*s_state.output != 'Z') {
|
||||
cl_assert_equal_i(*s_state.output, '\0');
|
||||
} else {
|
||||
*s_state.output = '\0';
|
||||
}
|
||||
size_t err_index = s_state.position - test->params;
|
||||
|
||||
#if DEBUG_PRINTING
|
||||
printf("parameter: \"%s\"\n", test->params);
|
||||
printf("filter_state: %jd %s\n", test->filter_state,
|
||||
test->time_was_until ? "until" : "since");
|
||||
printf("expect: \"%s\" err %d @ %zu eval@%jd\n", test->expect_str,
|
||||
test->expect_status, test->expect_index,
|
||||
test->expect_eval_time);
|
||||
printf("got : \"%s\" err %d @ %zu eval@%jd\n", s_output,
|
||||
s_error.status, err_index, s_cond.eval_time);
|
||||
#endif
|
||||
|
||||
if (s_error.status) {
|
||||
#if DEBUG_PRINTING
|
||||
printf("\"%s\"\n", test->params);
|
||||
printf("%*s^\n", (int)err_index + 1, "");
|
||||
if (s_error.status >= TemplateStringErrorStatusCount) {
|
||||
printf("Invalid status code\n");
|
||||
} else {
|
||||
printf("%s\n", s_error_strings[s_error.status]);
|
||||
}
|
||||
#endif
|
||||
cl_assert_equal_i(s_error.status, test->expect_status);
|
||||
cl_assert_equal_i(err_index, test->expect_index);
|
||||
}
|
||||
|
||||
cl_assert_equal_s(s_output, test->expect_str);
|
||||
cl_assert_equal_i(s_cond.eval_time, test->expect_eval_time);
|
||||
|
||||
#if DEBUG_PRINTING
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Test pipeline parser
|
||||
|
||||
static const struct {
|
||||
const char *instr;
|
||||
time_t intime;
|
||||
const char *expect_str;
|
||||
time_t expect_time;
|
||||
bool expect_rv;
|
||||
TemplateStringErrorStatus expect_status;
|
||||
size_t expect_index;
|
||||
} s_full_tests[] = {
|
||||
{ "Basicist test~", 1000000000,
|
||||
"Basicist test~",
|
||||
0,
|
||||
true,
|
||||
},
|
||||
{ "\\\\\\", 1000000000,
|
||||
"\\",
|
||||
EVAL_DEFAULT,
|
||||
false,
|
||||
TemplateStringErrorStatus_InvalidEscapeCharacter,
|
||||
3,
|
||||
},
|
||||
{ "\\e", 1000000000,
|
||||
"e",
|
||||
0,
|
||||
true,
|
||||
},
|
||||
{ "\\\\\\{}", 1000000000,
|
||||
"\\{}",
|
||||
0,
|
||||
true,
|
||||
},
|
||||
{ "\\\\{end()}", 1000000000,
|
||||
"\\",
|
||||
0,
|
||||
true,
|
||||
},
|
||||
{ "\\{end()}", 1000000000,
|
||||
"{end()}",
|
||||
0,
|
||||
true,
|
||||
},
|
||||
{ "Harder test {} bazza", 1000000000,
|
||||
"Harder test ",
|
||||
EVAL_DEFAULT,
|
||||
false,
|
||||
TemplateStringErrorStatus_NoResultGenerated,
|
||||
13,
|
||||
},
|
||||
{ "Failer {time_until}", 1000000000,
|
||||
"Failer ",
|
||||
EVAL_DEFAULT,
|
||||
false,
|
||||
TemplateStringErrorStatus_MissingOpeningParen,
|
||||
8,
|
||||
},
|
||||
{ "B {time_until(1)|format('\\\\')}", 0,
|
||||
"B \\",
|
||||
0,
|
||||
true,
|
||||
},
|
||||
{ "B {time_until(1)|format('\\%foo')}", 0,
|
||||
"B %foo",
|
||||
0,
|
||||
true,
|
||||
},
|
||||
{ "B {time_until(1)|format('%%foo')}", 0,
|
||||
"B %foo",
|
||||
0,
|
||||
true,
|
||||
},
|
||||
{ "B {time_until(1)|format('\\'')}", 0,
|
||||
"B '",
|
||||
0,
|
||||
true,
|
||||
},
|
||||
{ "B {time_until(1)|format('\\)}", 0,
|
||||
"B )}",
|
||||
EVAL_DEFAULT,
|
||||
false,
|
||||
TemplateStringErrorStatus_MissingClosingQuote,
|
||||
28,
|
||||
},
|
||||
{ "B {time_until(1)|format('%T')}", 0,
|
||||
"B 1",
|
||||
1,
|
||||
true,
|
||||
},
|
||||
{ "B {time_until(1)|format('%K')}", 0,
|
||||
"B ",
|
||||
EVAL_DEFAULT,
|
||||
false,
|
||||
TemplateStringErrorStatus_InvalidConversionSpecifier,
|
||||
26,
|
||||
},
|
||||
{ "B {time_until(1)|format('%f')}", 0,
|
||||
"B ",
|
||||
EVAL_DEFAULT,
|
||||
false,
|
||||
TemplateStringErrorStatus_InvalidConversionSpecifier,
|
||||
27,
|
||||
},
|
||||
{ "F {time_until(100)}", 1000000000,
|
||||
"F ",
|
||||
EVAL_DEFAULT,
|
||||
false,
|
||||
TemplateStringErrorStatus_NoResultGenerated,
|
||||
18,
|
||||
},
|
||||
{ "{end()", 1000000000,
|
||||
"",
|
||||
EVAL_DEFAULT,
|
||||
false,
|
||||
TemplateStringErrorStatus_MissingClosingBrace,
|
||||
6,
|
||||
},
|
||||
{ "{end(hurf", 1000000000,
|
||||
"",
|
||||
EVAL_DEFAULT,
|
||||
false,
|
||||
TemplateStringErrorStatus_MissingClosingParen,
|
||||
5,
|
||||
},
|
||||
{ "{end}", 1000000000,
|
||||
"",
|
||||
EVAL_DEFAULT,
|
||||
false,
|
||||
TemplateStringErrorStatus_MissingOpeningParen,
|
||||
1,
|
||||
},
|
||||
|
||||
{ "B {time_until(129666)|format('%T')}", 0,
|
||||
"B 12:01:06",
|
||||
1,
|
||||
true,
|
||||
},
|
||||
|
||||
{ "Countdown: {time_until(1)|format(>1d12H:'%0ud',<0S:'%-uS since',<60S:'%uS')} foof",
|
||||
10,
|
||||
"Countdown: 9 seconds since foof",
|
||||
10 + 1,
|
||||
true,
|
||||
},
|
||||
{ "Countdown: {time_until(129601)|format(>1d12H:'%0ud',<0S:'%-uS since',<60S:'%0uS')} foof",
|
||||
1,
|
||||
"Countdown: ",
|
||||
1 + 129601 - 60, // Time left until we hit <60S
|
||||
false,
|
||||
TemplateStringErrorStatus_CantResolve,
|
||||
80,
|
||||
},
|
||||
|
||||
{ "B {time_until(129666)|format('boop)I\\'m a filter')}", 0,
|
||||
"B boop)I'm a filter",
|
||||
0,
|
||||
true,
|
||||
},
|
||||
|
||||
{ "B {time_until(129666)|format('%T')} AND {time_until(129660)|format('%T')}", 0,
|
||||
"B 12:01:06 AND 12:01:00",
|
||||
1,
|
||||
true,
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
void test_template_string__full_test(void) {
|
||||
for(int i = 0; i < ARRAY_LENGTH(s_full_tests); i++) {
|
||||
TemplateStringVars vars = {};
|
||||
TemplateStringError err = {};
|
||||
TemplateStringEvalConditions cond = {};
|
||||
|
||||
vars.current_time = s_full_tests[i].intime;
|
||||
cond.eval_time = EVAL_FALL_THROUGH;
|
||||
|
||||
memset(s_output, 'Z', sizeof(s_output));
|
||||
bool rv = template_string_evaluate(s_full_tests[i].instr, s_output, sizeof(s_output),
|
||||
&cond, &vars, &err);
|
||||
#if DEBUG_PRINTING
|
||||
printf("instr: \"%s\"\n", s_full_tests[i].instr);
|
||||
printf("outstr: \"%s\"\n", s_output);
|
||||
printf("next_eval: %ld\n", cond.eval_time);
|
||||
printf("rv: %s\n", rv ? "true" : "false");
|
||||
if (!rv) {
|
||||
printf("err.status: %X\n", err.status);
|
||||
printf("err.index: %zu\n", err.index_in_string);
|
||||
printf("\"%s\"\n", s_full_tests[i].instr);
|
||||
printf("%*s^\n", (int)err.index_in_string + 1, "");
|
||||
if (err.status >= TemplateStringErrorStatusCount) {
|
||||
printf("Invalid status code\n");
|
||||
} else {
|
||||
printf("%s\n", s_error_strings[err.status]);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
cl_assert_equal_s(s_output, s_full_tests[i].expect_str);
|
||||
cl_assert_equal_i(rv, s_full_tests[i].expect_rv);
|
||||
cl_assert_equal_i(cond.eval_time, s_full_tests[i].expect_time);
|
||||
if (cond.eval_time != 0) {
|
||||
cl_assert_equal_b(cond.force_eval_on_time, true);
|
||||
} else {
|
||||
cl_assert_equal_b(cond.force_eval_on_time, false);
|
||||
}
|
||||
if (!rv) {
|
||||
cl_assert_equal_i(err.status, s_full_tests[i].expect_status);
|
||||
cl_assert_equal_i(err.index_in_string, s_full_tests[i].expect_index);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue