New test program 'test_conf', mostly transitional.
This aims to be a reasonably exhaustive test of what happens if you
set Conf values to various things, and then save your session, and
find out what ends up in the storage. Or vice versa.
Currently, the test program is written to match the existing
behaviour. The idea is that I can refactor the code that does the
loading and saving, and if this test still passes, I've probably done
it right.
However, in the long term, this test will be a liability: it's yet
another place you have to add every new config option. So my plan is
to get rid of it again once the refactorings I'm planning are
finished.
Or rather, I'll get rid of _that_ part of its functionality. I also
suspect I'll have added new kinds of consistency check by then, which
won't be a liability in the same way, and which I'll want to keep.
2023-09-22 12:57:50 +00:00
|
|
|
#define SUPERSEDE_FONTSPEC_FOR_TESTING
|
|
|
|
|
|
|
|
#include "putty.h"
|
|
|
|
#include "storage.h"
|
|
|
|
|
|
|
|
void modalfatalbox(const char *p, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
fprintf(stderr, "FATAL ERROR: ");
|
|
|
|
va_start(ap, p);
|
|
|
|
vfprintf(stderr, p, ap);
|
|
|
|
va_end(ap);
|
|
|
|
fputc('\n', stderr);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *platform_default_s(const char *name)
|
|
|
|
{ return NULL; }
|
|
|
|
bool platform_default_b(const char *name, bool def)
|
|
|
|
{ return def; }
|
|
|
|
int platform_default_i(const char *name, int def)
|
|
|
|
{ return def; }
|
|
|
|
FontSpec *platform_default_fontspec(const char *name)
|
|
|
|
{ return fontspec_new_default(); }
|
|
|
|
Filename *platform_default_filename(const char *name)
|
|
|
|
{ return filename_from_str(""); }
|
|
|
|
char *platform_get_x_display(void) { return NULL; }
|
|
|
|
|
|
|
|
void read_random_seed(noise_consumer_t consumer) {}
|
|
|
|
void write_random_seed(void *data, int len)
|
|
|
|
{ unreachable("no random seed in this application"); }
|
|
|
|
bool have_ssh_host_key(const char *hostname, int port,
|
|
|
|
const char *keytype) { return false; }
|
|
|
|
int check_stored_host_key(const char *hostname, int port,
|
|
|
|
const char *keytype, const char *key) { return 1; }
|
|
|
|
void store_host_key(Seat *seat, const char *hostname, int port,
|
|
|
|
const char *keytype, const char *key)
|
|
|
|
{ unreachable("no actual host keys in this application"); }
|
|
|
|
|
|
|
|
host_ca_enum *enum_host_ca_start(void) { return NULL; }
|
|
|
|
bool enum_host_ca_next(host_ca_enum *handle, strbuf *out) { return false; }
|
|
|
|
void enum_host_ca_finish(host_ca_enum *handle) {}
|
|
|
|
host_ca *host_ca_load(const char *name) { return NULL; }
|
|
|
|
|
|
|
|
void old_keyfile_warning(void) { }
|
|
|
|
|
|
|
|
const bool share_can_be_upstream = false;
|
|
|
|
const bool share_can_be_downstream = false;
|
|
|
|
|
|
|
|
struct FontSpec {
|
|
|
|
char *name;
|
|
|
|
};
|
|
|
|
|
|
|
|
FontSpec *fontspec_new(const char *name)
|
|
|
|
{
|
|
|
|
FontSpec *f = snew(FontSpec);
|
|
|
|
f->name = dupstr(name);
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
FontSpec *fontspec_new_default(void)
|
|
|
|
{
|
|
|
|
return fontspec_new("");
|
|
|
|
}
|
|
|
|
|
|
|
|
FontSpec *fontspec_copy(const FontSpec *f)
|
|
|
|
{
|
|
|
|
return fontspec_new(f->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void fontspec_free(FontSpec *f)
|
|
|
|
{
|
|
|
|
sfree(f->name);
|
|
|
|
sfree(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
void fontspec_serialise(BinarySink *bs, FontSpec *f)
|
|
|
|
{
|
|
|
|
put_asciz(bs, f->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
FontSpec *fontspec_deserialise(BinarySource *src)
|
|
|
|
{
|
|
|
|
return fontspec_new(get_asciz(src));
|
|
|
|
}
|
|
|
|
|
|
|
|
#define MAXKEY 16
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
SAVE_UNSET, SAVE_S, SAVE_I, SAVE_FONTSPEC, SAVE_FILENAME
|
|
|
|
} SaveType;
|
|
|
|
|
|
|
|
typedef struct SaveItem {
|
|
|
|
const char *key;
|
|
|
|
SaveType type;
|
|
|
|
union {
|
|
|
|
char sval[4096];
|
|
|
|
int ival;
|
|
|
|
};
|
|
|
|
} SaveItem;
|
|
|
|
|
|
|
|
struct settings_w {
|
|
|
|
size_t n;
|
|
|
|
SaveItem si[MAXKEY];
|
|
|
|
};
|
|
|
|
|
|
|
|
settings_w *open_settings_w(const char *sessionname, char **errmsg)
|
|
|
|
{ return NULL; }
|
|
|
|
void close_settings_w(settings_w *sw)
|
|
|
|
{ unreachable("we don't open and close in this test program"); }
|
|
|
|
settings_r *open_settings_r(const char *sessionname)
|
|
|
|
{ return NULL; }
|
|
|
|
void close_settings_r(settings_r *sr) { }
|
|
|
|
|
|
|
|
/* Work around lack of true snprintf before VS2015 */
|
|
|
|
#if defined _WINDOWS && \
|
|
|
|
!defined __MINGW32__ && \
|
|
|
|
!defined __WINE__ && \
|
|
|
|
_MSC_VER < 1900
|
|
|
|
#define snprintf _snprintf
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void write_setting_s(settings_w *sw, const char *key, const char *value)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < sw->n; i++) {
|
|
|
|
if (!strcmp(key, sw->si[i].key)) {
|
|
|
|
sw->si[i].type = SAVE_S;
|
|
|
|
snprintf(sw->si[i].sval, sizeof(sw->si[i].sval), "%s", value);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void write_setting_i(settings_w *sw, const char *key, int value)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < sw->n; i++) {
|
|
|
|
if (!strcmp(key, sw->si[i].key)) {
|
|
|
|
sw->si[i].type = SAVE_I;
|
|
|
|
sw->si[i].ival = value;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void write_setting_fontspec(settings_w *sw, const char *key, FontSpec *fs)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < sw->n; i++) {
|
|
|
|
if (!strcmp(key, sw->si[i].key)) {
|
|
|
|
sw->si[i].type = SAVE_FONTSPEC;
|
|
|
|
snprintf(sw->si[i].sval, sizeof(sw->si[i].sval), "%s", fs->name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void write_setting_filename(settings_w *sw, const char *key, Filename *fn)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < sw->n; i++) {
|
|
|
|
if (!strcmp(key, sw->si[i].key)) {
|
|
|
|
sw->si[i].type = SAVE_FILENAME;
|
|
|
|
snprintf(sw->si[i].sval, sizeof(sw->si[i].sval), "%s",
|
|
|
|
filename_to_str(fn));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct settings_r {
|
|
|
|
size_t n;
|
|
|
|
SaveItem si[MAXKEY];
|
|
|
|
};
|
|
|
|
|
|
|
|
char *read_setting_s(settings_r *sr, const char *key)
|
|
|
|
{
|
|
|
|
if (sr)
|
|
|
|
for (size_t i = 0; i < sr->n; i++)
|
|
|
|
if (!strcmp(key, sr->si[i].key) && sr->si[i].type == SAVE_S)
|
|
|
|
return dupstr(sr->si[i].sval);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int read_setting_i(settings_r *sr, const char *key, int defvalue)
|
|
|
|
{
|
|
|
|
if (sr)
|
|
|
|
for (size_t i = 0; i < sr->n; i++)
|
|
|
|
if (!strcmp(key, sr->si[i].key) && sr->si[i].type == SAVE_I)
|
|
|
|
return sr->si[i].ival;
|
|
|
|
return defvalue;
|
|
|
|
}
|
|
|
|
|
|
|
|
FontSpec *read_setting_fontspec(settings_r *sr, const char *key)
|
|
|
|
{
|
|
|
|
if (sr)
|
|
|
|
for (size_t i = 0; i < sr->n; i++)
|
|
|
|
if (!strcmp(key, sr->si[i].key) && sr->si[i].type == SAVE_FONTSPEC)
|
|
|
|
return fontspec_new(sr->si[i].sval);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Filename *read_setting_filename(settings_r *sr, const char *key)
|
|
|
|
{
|
|
|
|
if (sr)
|
|
|
|
for (size_t i = 0; i < sr->n; i++)
|
|
|
|
if (!strcmp(key, sr->si[i].key) && sr->si[i].type == SAVE_FILENAME)
|
|
|
|
return filename_from_str(sr->si[i].sval);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void del_settings(const char *sessionname) {}
|
|
|
|
|
|
|
|
settings_e *enum_settings_start(void)
|
|
|
|
{ return NULL; }
|
|
|
|
bool enum_settings_next(settings_e *handle, strbuf *out)
|
|
|
|
{ unreachable("where did you get a settings_e from?"); }
|
|
|
|
void enum_settings_finish(settings_e *handle)
|
|
|
|
{ unreachable("where did you get a settings_e from?"); }
|
|
|
|
|
|
|
|
static int nfails = 0;
|
|
|
|
|
|
|
|
void test_str_simple(int confid, const char *saveid, const char *defexp)
|
|
|
|
{
|
|
|
|
Conf *conf = conf_new();
|
|
|
|
|
|
|
|
do_defaults(NULL, conf);
|
|
|
|
const char *defgot = conf_get_str(conf, confid);
|
|
|
|
if (0 != strcmp(defgot, defexp)) {
|
|
|
|
printf("fail test_str_simple(%s): default = '%s', expected '%s'\n",
|
|
|
|
saveid, defgot, defexp);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
settings_w sw = {
|
|
|
|
.n = 1,
|
|
|
|
.si[0].key = saveid,
|
|
|
|
.si[0].type = SAVE_UNSET,
|
|
|
|
};
|
|
|
|
static const char *const teststrings[] = { "foo", "bar" };
|
|
|
|
const char *teststring = teststrings[i];
|
|
|
|
conf_set_str(conf, confid, teststring);
|
|
|
|
save_open_settings(&sw, conf);
|
|
|
|
if (sw.si[0].type != SAVE_S) {
|
|
|
|
printf("fail test_str_simple(%s): saved type = %d, expected %d\n",
|
|
|
|
saveid, sw.si[0].type, SAVE_S);
|
|
|
|
nfails++;
|
|
|
|
} else if (0 != strcmp(sw.si[0].sval, teststring)) {
|
|
|
|
printf("fail test_str_simple(%s): "
|
|
|
|
"saved string = '%s', expected '%s'\n",
|
|
|
|
saveid, sw.si[0].sval, teststring);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
|
|
|
conf_clear(conf);
|
|
|
|
settings_r sr = {
|
|
|
|
.n = 1,
|
|
|
|
.si[0].key = saveid,
|
|
|
|
.si[0].type = SAVE_S,
|
|
|
|
};
|
|
|
|
snprintf(sr.si[0].sval, sizeof(sr.si[0].sval), "%s", teststring);
|
|
|
|
load_open_settings(&sr, conf);
|
|
|
|
const char *loaded = conf_get_str(conf, confid);
|
|
|
|
if (0 != strcmp(loaded, teststring)) {
|
|
|
|
printf("fail test_str_simple(%s): "
|
|
|
|
"loaded string = '%s', expected '%s'\n",
|
|
|
|
saveid, loaded, teststring);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
conf_free(conf);
|
|
|
|
}
|
|
|
|
|
Add two new string types to the Conf system.
This begins the process of making PuTTY more able to handle Unicode
strings as a first-class type in its configuration. One of the new
types, CONF_TYPE_UTF8, looks physically just like CONF_TYPE_STR but
the semantics are that it's definitely encoded in UTF-8, instead of
'shrug, whatever the system locale's encoding is'.
Unfortunately, we can't yet switch over any Conf items to having that
type, because our data representations in saved configuration (both on
Unix and Windows) store char strings in the system encoding. So we'll
have to change that representation at the same time, which risks
breaking backwards compatibility with old PuTTYs reading the same
configuration.
So the other new type, CONF_TYPE_STR_AMBI, is intended as a
transitional form, recording a configuration setting that _might_ be
explicitly UTF-8 or might have the legacy 'shrug, whatever' semantics,
depending on where we got it from.
My general migration plan is that first I _enable_ Unicode support in
a Conf item, by turning it into STR_AMBI; the Unicode version of the
string (if any) is saved in a new location, and a best-effort
local-charset version is saved where it's always been. That way new
PuTTY can read the Unicode version, and old PuTTY reading that
configuration will behave no worse than it would have done already.
It would be nice to think that in the far future we've migrated
everything to STR_AMBI and can move them all to mandatory UTF-8,
obsoleting the old configuration. I think it's more likely we'll never
get there. But at least _new_ Conf items, with no backwards
compatibility requirement in the first place, can be CONF_TYPE_UTF8
where appropriate.
(In conf_get_str_ambi(), I considered making it mandatory via assert()
to pass the 'utf8' output pointer as non-NULL, to defend against lazy
adaptation of existing code by just changing the function call. But in
fact I think there's a legitimate use case for not caring if the
output is UTF-8 or not, because some of the existing SSH code
currently just shoves strings like usernames directly on to the wire
whether they're in the right encoding or not; so if you want to do the
correct UTF-8 thing where possible and preserve legacy behaviour if
not, then treating both classes of string the same _is_ the right
thing to do.)
This also requires linking the Unicode support into many Unix
applications that hadn't previously needed it.
2024-09-23 11:00:37 +00:00
|
|
|
void test_utf8_simple(int confid, const char *saveid, const char *defexp)
|
|
|
|
{
|
|
|
|
Conf *conf = conf_new();
|
|
|
|
|
|
|
|
do_defaults(NULL, conf);
|
|
|
|
const char *defgot = conf_get_utf8(conf, confid);
|
|
|
|
if (0 != strcmp(defgot, defexp)) {
|
|
|
|
printf("fail test_utf8_simple(%s): default = '%s', expected '%s'\n",
|
|
|
|
saveid, defgot, defexp);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
settings_w sw = {
|
|
|
|
.n = 1,
|
|
|
|
.si[0].key = saveid,
|
|
|
|
.si[0].type = SAVE_UNSET,
|
|
|
|
};
|
|
|
|
static const char *const teststrings[] = { "foo", "bar" };
|
|
|
|
const char *teststring = teststrings[i];
|
|
|
|
conf_set_utf8(conf, confid, teststring);
|
|
|
|
save_open_settings(&sw, conf);
|
|
|
|
if (sw.si[0].type != SAVE_S) {
|
|
|
|
printf("fail test_utf8_simple(%s): saved type = %d, expected %d\n",
|
|
|
|
saveid, sw.si[0].type, SAVE_S);
|
|
|
|
nfails++;
|
|
|
|
} else if (0 != strcmp(sw.si[0].sval, teststring)) {
|
|
|
|
printf("fail test_utf8_simple(%s): "
|
|
|
|
"saved string = '%s', expected '%s'\n",
|
|
|
|
saveid, sw.si[0].sval, teststring);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
|
|
|
conf_clear(conf);
|
|
|
|
settings_r sr = {
|
|
|
|
.n = 1,
|
|
|
|
.si[0].key = saveid,
|
|
|
|
.si[0].type = SAVE_S,
|
|
|
|
};
|
|
|
|
snprintf(sr.si[0].sval, sizeof(sr.si[0].sval), "%s", teststring);
|
|
|
|
load_open_settings(&sr, conf);
|
|
|
|
const char *loaded = conf_get_utf8(conf, confid);
|
|
|
|
if (0 != strcmp(loaded, teststring)) {
|
|
|
|
printf("fail test_utf8_simple(%s): "
|
|
|
|
"loaded string = '%s', expected '%s'\n",
|
|
|
|
saveid, loaded, teststring);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
conf_free(conf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_str_ambi_simple(int confid, const char *saveid,
|
|
|
|
const char *defexp, bool defutf8)
|
|
|
|
{
|
|
|
|
Conf *conf = conf_new();
|
|
|
|
bool utf8;
|
|
|
|
|
|
|
|
do_defaults(NULL, conf);
|
|
|
|
const char *defgot = conf_get_str_ambi(conf, confid, &utf8);
|
|
|
|
if (0 != strcmp(defgot, defexp) || utf8 != defutf8) {
|
|
|
|
printf("fail test_str_ambi_simple(%s): "
|
|
|
|
"default = '%s' (%s), expected '%s' (%s)\n",
|
|
|
|
saveid, defgot, utf8 ? "native" : "UTF-8",
|
|
|
|
defexp, defutf8 ? "native" : "UTF-8");
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
settings_w sw = {
|
|
|
|
.n = 1,
|
|
|
|
.si[0].key = saveid,
|
|
|
|
.si[0].type = SAVE_UNSET,
|
|
|
|
};
|
|
|
|
static const char *const teststrings[] = { "foo", "bar" };
|
|
|
|
const char *teststring = teststrings[i];
|
|
|
|
conf_set_str(conf, confid, teststring);
|
|
|
|
save_open_settings(&sw, conf);
|
|
|
|
if (sw.si[0].type != SAVE_S) {
|
|
|
|
printf("fail test_str_ambi_simple(%s): "
|
|
|
|
"saved type = %d, expected %d\n",
|
|
|
|
saveid, sw.si[0].type, SAVE_S);
|
|
|
|
nfails++;
|
|
|
|
} else if (0 != strcmp(sw.si[0].sval, teststring)) {
|
|
|
|
printf("fail test_str_ambi_simple(%s): "
|
|
|
|
"saved string = '%s', expected '%s'\n",
|
|
|
|
saveid, sw.si[0].sval, teststring);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
|
|
|
conf_clear(conf);
|
|
|
|
settings_r sr = {
|
|
|
|
.n = 1,
|
|
|
|
.si[0].key = saveid,
|
|
|
|
.si[0].type = SAVE_S,
|
|
|
|
};
|
|
|
|
snprintf(sr.si[0].sval, sizeof(sr.si[0].sval), "%s", teststring);
|
|
|
|
load_open_settings(&sr, conf);
|
|
|
|
const char *loaded = conf_get_str_ambi(conf, confid, &utf8);
|
|
|
|
if (0 != strcmp(loaded, teststring) || utf8) {
|
|
|
|
printf("fail test_str_ambi_simple(%s): "
|
|
|
|
"loaded string = '%s' (%s), expected '%s' (native)\n",
|
|
|
|
saveid, loaded, utf8 ? "native" : "UTF-8", teststring);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
conf_free(conf);
|
|
|
|
}
|
|
|
|
|
New test program 'test_conf', mostly transitional.
This aims to be a reasonably exhaustive test of what happens if you
set Conf values to various things, and then save your session, and
find out what ends up in the storage. Or vice versa.
Currently, the test program is written to match the existing
behaviour. The idea is that I can refactor the code that does the
loading and saving, and if this test still passes, I've probably done
it right.
However, in the long term, this test will be a liability: it's yet
another place you have to add every new config option. So my plan is
to get rid of it again once the refactorings I'm planning are
finished.
Or rather, I'll get rid of _that_ part of its functionality. I also
suspect I'll have added new kinds of consistency check by then, which
won't be a liability in the same way, and which I'll want to keep.
2023-09-22 12:57:50 +00:00
|
|
|
void test_int_simple(int confid, const char *saveid, int defexp)
|
|
|
|
{
|
|
|
|
Conf *conf = conf_new();
|
|
|
|
|
|
|
|
do_defaults(NULL, conf);
|
|
|
|
int defgot = conf_get_int(conf, confid);
|
|
|
|
if (defgot != defexp) {
|
|
|
|
printf("fail test_int_simple(%s): default = %d, expected %d\n",
|
|
|
|
saveid, defgot, defexp);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
settings_w sw = {
|
|
|
|
.n = 1,
|
|
|
|
.si[0].key = saveid,
|
|
|
|
.si[0].type = SAVE_UNSET,
|
|
|
|
};
|
|
|
|
static const int testints[] = { 12345, 54321 };
|
|
|
|
int testint = testints[i];
|
|
|
|
conf_set_int(conf, confid, testint);
|
|
|
|
save_open_settings(&sw, conf);
|
|
|
|
if (sw.si[0].type != SAVE_I) {
|
|
|
|
printf("fail test_int_simple(%s): saved type = %d, expected %d\n",
|
|
|
|
saveid, sw.si[0].type, SAVE_I);
|
|
|
|
nfails++;
|
|
|
|
} else if (sw.si[0].ival != testint) {
|
|
|
|
printf("fail test_int_simple(%s): "
|
|
|
|
"saved integer = %d, expected %d\n",
|
|
|
|
saveid, sw.si[0].ival, testint);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
|
|
|
conf_clear(conf);
|
|
|
|
settings_r sr = {
|
|
|
|
.n = 1,
|
|
|
|
.si[0].key = saveid,
|
|
|
|
.si[0].type = SAVE_I,
|
|
|
|
.si[0].ival = testint,
|
|
|
|
};
|
|
|
|
load_open_settings(&sr, conf);
|
|
|
|
int loaded = conf_get_int(conf, confid);
|
|
|
|
if (loaded != testint) {
|
|
|
|
printf("fail test_int_simple(%s): "
|
|
|
|
"loaded integer = %d, expected %d\n",
|
|
|
|
saveid, loaded, testint);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
conf_free(conf);
|
|
|
|
}
|
|
|
|
|
Add ability to specify custom load and save separately.
This allows a couple more settings to be treated automatically on
save, which are more complicated on load because they still honour
older alternative save keywords.
In particular, CONF_proxy_type and CONF_remote_qtitle_action now have
explicit enum mappings. These were needed for the automated save code,
but also, I've rewritten the custom load code to use them too. This
decouples the storage format of those settings from the order of
values in the internal enum, which is generally an advantage of
specifying storage enums explicitly.
Those two settings weren't already tested by test_conf, because I
wasn't changing them in previous commits. Now I've added extra code
that does test them, and verified it works when backported to commit
b567c9b2b5e159f where I introduced test_conf before beginning the main
refactoring.
A setting can also be specified explicitly as not loaded and saved at
all. There were quite a few commented that way, but now there's a
machine-readable indication of it.
test_conf will now check that all these settings make sense together -
things shouldn't have a save keyword unless they use it, and should
have one if they don't, and shouldn't specify combinations of options
that conflict.
(For that reason, test_conf is now also running the consistency check
before the main test, so that a missing keyword will cause an error
message _before_ it causes a segfault, saving some debugging!)
2023-09-22 15:04:25 +00:00
|
|
|
void test_int_translated_internal(
|
|
|
|
int confid, const char *saveid, bool test_save, bool test_load,
|
|
|
|
void (*load_prepare)(settings_r *), int defexp, va_list ap)
|
New test program 'test_conf', mostly transitional.
This aims to be a reasonably exhaustive test of what happens if you
set Conf values to various things, and then save your session, and
find out what ends up in the storage. Or vice versa.
Currently, the test program is written to match the existing
behaviour. The idea is that I can refactor the code that does the
loading and saving, and if this test still passes, I've probably done
it right.
However, in the long term, this test will be a liability: it's yet
another place you have to add every new config option. So my plan is
to get rid of it again once the refactorings I'm planning are
finished.
Or rather, I'll get rid of _that_ part of its functionality. I also
suspect I'll have added new kinds of consistency check by then, which
won't be a liability in the same way, and which I'll want to keep.
2023-09-22 12:57:50 +00:00
|
|
|
{
|
|
|
|
Conf *conf = conf_new();
|
|
|
|
|
|
|
|
do_defaults(NULL, conf);
|
|
|
|
int defgot = conf_get_int(conf, confid);
|
|
|
|
if (defgot != defexp) {
|
|
|
|
printf("fail test_int_translated(%s): default = %d, expected %d\n",
|
|
|
|
saveid, defgot, defexp);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
|
|
|
int confval = va_arg(ap, int);
|
|
|
|
while (confval != -1) {
|
|
|
|
int storageval = va_arg(ap, int);
|
Add ability to specify custom load and save separately.
This allows a couple more settings to be treated automatically on
save, which are more complicated on load because they still honour
older alternative save keywords.
In particular, CONF_proxy_type and CONF_remote_qtitle_action now have
explicit enum mappings. These were needed for the automated save code,
but also, I've rewritten the custom load code to use them too. This
decouples the storage format of those settings from the order of
values in the internal enum, which is generally an advantage of
specifying storage enums explicitly.
Those two settings weren't already tested by test_conf, because I
wasn't changing them in previous commits. Now I've added extra code
that does test them, and verified it works when backported to commit
b567c9b2b5e159f where I introduced test_conf before beginning the main
refactoring.
A setting can also be specified explicitly as not loaded and saved at
all. There were quite a few commented that way, but now there's a
machine-readable indication of it.
test_conf will now check that all these settings make sense together -
things shouldn't have a save keyword unless they use it, and should
have one if they don't, and shouldn't specify combinations of options
that conflict.
(For that reason, test_conf is now also running the consistency check
before the main test, so that a missing keyword will cause an error
message _before_ it causes a segfault, saving some debugging!)
2023-09-22 15:04:25 +00:00
|
|
|
|
|
|
|
if (test_save) {
|
|
|
|
settings_w sw = {
|
|
|
|
.n = 1,
|
|
|
|
.si[0].key = saveid,
|
|
|
|
.si[0].type = SAVE_UNSET,
|
|
|
|
};
|
|
|
|
conf_set_int(conf, confid, confval);
|
|
|
|
save_open_settings(&sw, conf);
|
|
|
|
if (sw.si[0].type != SAVE_I) {
|
|
|
|
printf("fail test_int_translated(%s): "
|
|
|
|
"saved type = %d, expected %d\n",
|
|
|
|
saveid, sw.si[0].type, SAVE_I);
|
|
|
|
nfails++;
|
|
|
|
} else if (sw.si[0].ival != storageval) {
|
|
|
|
printf("fail test_int_translated(%s.%d.%d): "
|
|
|
|
"saved integer = %d, expected %d\n",
|
|
|
|
saveid, confval, storageval, sw.si[0].ival, storageval);
|
|
|
|
nfails++;
|
|
|
|
}
|
New test program 'test_conf', mostly transitional.
This aims to be a reasonably exhaustive test of what happens if you
set Conf values to various things, and then save your session, and
find out what ends up in the storage. Or vice versa.
Currently, the test program is written to match the existing
behaviour. The idea is that I can refactor the code that does the
loading and saving, and if this test still passes, I've probably done
it right.
However, in the long term, this test will be a liability: it's yet
another place you have to add every new config option. So my plan is
to get rid of it again once the refactorings I'm planning are
finished.
Or rather, I'll get rid of _that_ part of its functionality. I also
suspect I'll have added new kinds of consistency check by then, which
won't be a liability in the same way, and which I'll want to keep.
2023-09-22 12:57:50 +00:00
|
|
|
}
|
|
|
|
|
Add ability to specify custom load and save separately.
This allows a couple more settings to be treated automatically on
save, which are more complicated on load because they still honour
older alternative save keywords.
In particular, CONF_proxy_type and CONF_remote_qtitle_action now have
explicit enum mappings. These were needed for the automated save code,
but also, I've rewritten the custom load code to use them too. This
decouples the storage format of those settings from the order of
values in the internal enum, which is generally an advantage of
specifying storage enums explicitly.
Those two settings weren't already tested by test_conf, because I
wasn't changing them in previous commits. Now I've added extra code
that does test them, and verified it works when backported to commit
b567c9b2b5e159f where I introduced test_conf before beginning the main
refactoring.
A setting can also be specified explicitly as not loaded and saved at
all. There were quite a few commented that way, but now there's a
machine-readable indication of it.
test_conf will now check that all these settings make sense together -
things shouldn't have a save keyword unless they use it, and should
have one if they don't, and shouldn't specify combinations of options
that conflict.
(For that reason, test_conf is now also running the consistency check
before the main test, so that a missing keyword will cause an error
message _before_ it causes a segfault, saving some debugging!)
2023-09-22 15:04:25 +00:00
|
|
|
if (test_load) {
|
|
|
|
conf_clear(conf);
|
|
|
|
settings_r sr = {
|
|
|
|
.n = 1,
|
|
|
|
.si[0].key = saveid,
|
|
|
|
.si[0].type = SAVE_I,
|
|
|
|
.si[0].ival = storageval,
|
|
|
|
};
|
|
|
|
if (load_prepare)
|
|
|
|
load_prepare(&sr);
|
|
|
|
load_open_settings(&sr, conf);
|
|
|
|
int loaded = conf_get_int(conf, confid);
|
|
|
|
if (loaded != confval) {
|
|
|
|
printf("fail test_int_translated(%s.%d.%d): "
|
|
|
|
"loaded integer = %d, expected %d\n",
|
|
|
|
saveid, confval, storageval, loaded, confval);
|
|
|
|
nfails++;
|
|
|
|
}
|
New test program 'test_conf', mostly transitional.
This aims to be a reasonably exhaustive test of what happens if you
set Conf values to various things, and then save your session, and
find out what ends up in the storage. Or vice versa.
Currently, the test program is written to match the existing
behaviour. The idea is that I can refactor the code that does the
loading and saving, and if this test still passes, I've probably done
it right.
However, in the long term, this test will be a liability: it's yet
another place you have to add every new config option. So my plan is
to get rid of it again once the refactorings I'm planning are
finished.
Or rather, I'll get rid of _that_ part of its functionality. I also
suspect I'll have added new kinds of consistency check by then, which
won't be a liability in the same way, and which I'll want to keep.
2023-09-22 12:57:50 +00:00
|
|
|
}
|
Add ability to specify custom load and save separately.
This allows a couple more settings to be treated automatically on
save, which are more complicated on load because they still honour
older alternative save keywords.
In particular, CONF_proxy_type and CONF_remote_qtitle_action now have
explicit enum mappings. These were needed for the automated save code,
but also, I've rewritten the custom load code to use them too. This
decouples the storage format of those settings from the order of
values in the internal enum, which is generally an advantage of
specifying storage enums explicitly.
Those two settings weren't already tested by test_conf, because I
wasn't changing them in previous commits. Now I've added extra code
that does test them, and verified it works when backported to commit
b567c9b2b5e159f where I introduced test_conf before beginning the main
refactoring.
A setting can also be specified explicitly as not loaded and saved at
all. There were quite a few commented that way, but now there's a
machine-readable indication of it.
test_conf will now check that all these settings make sense together -
things shouldn't have a save keyword unless they use it, and should
have one if they don't, and shouldn't specify combinations of options
that conflict.
(For that reason, test_conf is now also running the consistency check
before the main test, so that a missing keyword will cause an error
message _before_ it causes a segfault, saving some debugging!)
2023-09-22 15:04:25 +00:00
|
|
|
|
New test program 'test_conf', mostly transitional.
This aims to be a reasonably exhaustive test of what happens if you
set Conf values to various things, and then save your session, and
find out what ends up in the storage. Or vice versa.
Currently, the test program is written to match the existing
behaviour. The idea is that I can refactor the code that does the
loading and saving, and if this test still passes, I've probably done
it right.
However, in the long term, this test will be a liability: it's yet
another place you have to add every new config option. So my plan is
to get rid of it again once the refactorings I'm planning are
finished.
Or rather, I'll get rid of _that_ part of its functionality. I also
suspect I'll have added new kinds of consistency check by then, which
won't be a liability in the same way, and which I'll want to keep.
2023-09-22 12:57:50 +00:00
|
|
|
confval = va_arg(ap, int);
|
|
|
|
}
|
|
|
|
|
|
|
|
conf_free(conf);
|
|
|
|
}
|
|
|
|
|
Add ability to specify custom load and save separately.
This allows a couple more settings to be treated automatically on
save, which are more complicated on load because they still honour
older alternative save keywords.
In particular, CONF_proxy_type and CONF_remote_qtitle_action now have
explicit enum mappings. These were needed for the automated save code,
but also, I've rewritten the custom load code to use them too. This
decouples the storage format of those settings from the order of
values in the internal enum, which is generally an advantage of
specifying storage enums explicitly.
Those two settings weren't already tested by test_conf, because I
wasn't changing them in previous commits. Now I've added extra code
that does test them, and verified it works when backported to commit
b567c9b2b5e159f where I introduced test_conf before beginning the main
refactoring.
A setting can also be specified explicitly as not loaded and saved at
all. There were quite a few commented that way, but now there's a
machine-readable indication of it.
test_conf will now check that all these settings make sense together -
things shouldn't have a save keyword unless they use it, and should
have one if they don't, and shouldn't specify combinations of options
that conflict.
(For that reason, test_conf is now also running the consistency check
before the main test, so that a missing keyword will cause an error
message _before_ it causes a segfault, saving some debugging!)
2023-09-22 15:04:25 +00:00
|
|
|
void test_int_translated(int confid, const char *saveid, int defexp, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, defexp);
|
|
|
|
test_int_translated_internal(confid, saveid, true, true, NULL, defexp, ap);
|
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_int_translated_load_legacy(
|
|
|
|
int confid, const char *saveid, void (*load_prepare)(settings_r *),
|
|
|
|
int defexp, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, defexp);
|
|
|
|
test_int_translated_internal(confid, saveid, false, true, load_prepare,
|
|
|
|
defexp, ap);
|
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
New test program 'test_conf', mostly transitional.
This aims to be a reasonably exhaustive test of what happens if you
set Conf values to various things, and then save your session, and
find out what ends up in the storage. Or vice versa.
Currently, the test program is written to match the existing
behaviour. The idea is that I can refactor the code that does the
loading and saving, and if this test still passes, I've probably done
it right.
However, in the long term, this test will be a liability: it's yet
another place you have to add every new config option. So my plan is
to get rid of it again once the refactorings I'm planning are
finished.
Or rather, I'll get rid of _that_ part of its functionality. I also
suspect I'll have added new kinds of consistency check by then, which
won't be a liability in the same way, and which I'll want to keep.
2023-09-22 12:57:50 +00:00
|
|
|
void test_bool_simple(int confid, const char *saveid, bool defexp)
|
|
|
|
{
|
|
|
|
Conf *conf = conf_new();
|
|
|
|
|
|
|
|
do_defaults(NULL, conf);
|
|
|
|
bool defgot = conf_get_bool(conf, confid);
|
|
|
|
if (defgot != defexp) {
|
|
|
|
printf("fail test_bool_simple(%s): default = %d, expected %d\n",
|
|
|
|
saveid, defgot, defexp);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
settings_w sw = {
|
|
|
|
.n = 1,
|
|
|
|
.si[0].key = saveid,
|
|
|
|
.si[0].type = SAVE_UNSET,
|
|
|
|
};
|
|
|
|
static const bool testbools[] = { false, true };
|
|
|
|
bool testbool = testbools[i];
|
|
|
|
conf_set_bool(conf, confid, testbool);
|
|
|
|
save_open_settings(&sw, conf);
|
|
|
|
if (sw.si[0].type != SAVE_I) {
|
|
|
|
printf("fail test_bool_simple(%s): saved type = %d, expected %d\n",
|
|
|
|
saveid, sw.si[0].type, SAVE_I);
|
|
|
|
nfails++;
|
|
|
|
} else if (sw.si[0].ival != testbool) {
|
|
|
|
printf("fail test_bool_simple(%s): "
|
|
|
|
"saved integer = %d, expected %d\n",
|
|
|
|
saveid, sw.si[0].ival, testbool);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
|
|
|
conf_clear(conf);
|
|
|
|
settings_r sr = {
|
|
|
|
.n = 1,
|
|
|
|
.si[0].key = saveid,
|
|
|
|
.si[0].type = SAVE_I,
|
|
|
|
.si[0].ival = testbool,
|
|
|
|
};
|
|
|
|
load_open_settings(&sr, conf);
|
|
|
|
bool loaded = conf_get_bool(conf, confid);
|
|
|
|
if (loaded != testbool) {
|
|
|
|
printf("fail test_bool_simple(%s): "
|
|
|
|
"loaded boolean = %d, expected %d\n",
|
|
|
|
saveid, loaded, testbool);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
conf_free(conf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_file_simple(int confid, const char *saveid)
|
|
|
|
{
|
|
|
|
Conf *conf = conf_new();
|
|
|
|
|
|
|
|
do_defaults(NULL, conf);
|
|
|
|
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
settings_w sw = {
|
|
|
|
.n = 1,
|
|
|
|
.si[0].key = saveid,
|
|
|
|
.si[0].type = SAVE_UNSET,
|
|
|
|
};
|
|
|
|
static const char *const teststrings[] = { "foo", "bar" };
|
|
|
|
const char *teststring = teststrings[i];
|
|
|
|
Filename *testfn = filename_from_str(teststring);
|
|
|
|
conf_set_filename(conf, confid, testfn);
|
|
|
|
filename_free(testfn);
|
|
|
|
save_open_settings(&sw, conf);
|
|
|
|
if (sw.si[0].type != SAVE_FILENAME) {
|
|
|
|
printf("fail test_file_simple(%s): saved type = %d, expected %d\n",
|
|
|
|
saveid, sw.si[0].type, SAVE_FILENAME);
|
|
|
|
nfails++;
|
|
|
|
} else if (0 != strcmp(sw.si[0].sval, teststring)) {
|
|
|
|
printf("fail test_file_simple(%s): "
|
|
|
|
"saved string = '%s', expected '%s'\n",
|
|
|
|
saveid, sw.si[0].sval, teststring);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
|
|
|
conf_clear(conf);
|
|
|
|
settings_r sr = {
|
|
|
|
.n = 1,
|
|
|
|
.si[0].key = saveid,
|
|
|
|
.si[0].type = SAVE_FILENAME,
|
|
|
|
};
|
|
|
|
snprintf(sr.si[0].sval, sizeof(sr.si[0].sval), "%s", teststring);
|
|
|
|
load_open_settings(&sr, conf);
|
|
|
|
const char *loaded = filename_to_str(conf_get_filename(conf, confid));
|
|
|
|
if (0 != strcmp(loaded, teststring)) {
|
|
|
|
printf("fail test_file_simple(%s): "
|
|
|
|
"loaded string = '%s', expected '%s'\n",
|
|
|
|
saveid, loaded, teststring);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
conf_free(conf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void test_font_simple(int confid, const char *saveid)
|
|
|
|
{
|
|
|
|
Conf *conf = conf_new();
|
|
|
|
|
|
|
|
do_defaults(NULL, conf);
|
|
|
|
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
settings_w sw = {
|
|
|
|
.n = 1,
|
|
|
|
.si[0].key = saveid,
|
|
|
|
.si[0].type = SAVE_UNSET,
|
|
|
|
};
|
|
|
|
static const char *const teststrings[] = { "foo", "bar" };
|
|
|
|
const char *teststring = teststrings[i];
|
|
|
|
FontSpec *testfs = fontspec_new(teststring);
|
|
|
|
conf_set_fontspec(conf, confid, testfs);
|
|
|
|
fontspec_free(testfs);
|
|
|
|
save_open_settings(&sw, conf);
|
|
|
|
if (sw.si[0].type != SAVE_FONTSPEC) {
|
|
|
|
printf("fail test_font_simple(%s): saved type = %d, expected %d\n",
|
|
|
|
saveid, sw.si[0].type, SAVE_FONTSPEC);
|
|
|
|
nfails++;
|
|
|
|
} else if (0 != strcmp(sw.si[0].sval, teststring)) {
|
|
|
|
printf("fail test_font_simple(%s): "
|
|
|
|
"saved string = '%s', expected '%s'\n",
|
|
|
|
saveid, sw.si[0].sval, teststring);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
|
|
|
conf_clear(conf);
|
|
|
|
settings_r sr = {
|
|
|
|
.n = 1,
|
|
|
|
.si[0].key = saveid,
|
|
|
|
.si[0].type = SAVE_FONTSPEC,
|
|
|
|
};
|
|
|
|
snprintf(sr.si[0].sval, sizeof(sr.si[0].sval), "%s", teststring);
|
|
|
|
load_open_settings(&sr, conf);
|
|
|
|
const char *loaded = conf_get_fontspec(conf, confid)->name;
|
|
|
|
if (0 != strcmp(loaded, teststring)) {
|
|
|
|
printf("fail test_file_simple(%s): "
|
|
|
|
"loaded string = '%s', expected '%s'\n",
|
|
|
|
saveid, loaded, teststring);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
conf_free(conf);
|
|
|
|
}
|
|
|
|
|
Add ability to specify custom load and save separately.
This allows a couple more settings to be treated automatically on
save, which are more complicated on load because they still honour
older alternative save keywords.
In particular, CONF_proxy_type and CONF_remote_qtitle_action now have
explicit enum mappings. These were needed for the automated save code,
but also, I've rewritten the custom load code to use them too. This
decouples the storage format of those settings from the order of
values in the internal enum, which is generally an advantage of
specifying storage enums explicitly.
Those two settings weren't already tested by test_conf, because I
wasn't changing them in previous commits. Now I've added extra code
that does test them, and verified it works when backported to commit
b567c9b2b5e159f where I introduced test_conf before beginning the main
refactoring.
A setting can also be specified explicitly as not loaded and saved at
all. There were quite a few commented that way, but now there's a
machine-readable indication of it.
test_conf will now check that all these settings make sense together -
things shouldn't have a save keyword unless they use it, and should
have one if they don't, and shouldn't specify combinations of options
that conflict.
(For that reason, test_conf is now also running the consistency check
before the main test, so that a missing keyword will cause an error
message _before_ it causes a segfault, saving some debugging!)
2023-09-22 15:04:25 +00:00
|
|
|
static void load_prepare_socks4(settings_r *sr)
|
|
|
|
{
|
|
|
|
size_t pos = sr->n++;
|
|
|
|
sr->si[pos].key = "ProxySOCKSVersion";
|
|
|
|
sr->si[pos].type = SAVE_I;
|
|
|
|
sr->si[pos].ival = 4;
|
|
|
|
}
|
|
|
|
|
New test program 'test_conf', mostly transitional.
This aims to be a reasonably exhaustive test of what happens if you
set Conf values to various things, and then save your session, and
find out what ends up in the storage. Or vice versa.
Currently, the test program is written to match the existing
behaviour. The idea is that I can refactor the code that does the
loading and saving, and if this test still passes, I've probably done
it right.
However, in the long term, this test will be a liability: it's yet
another place you have to add every new config option. So my plan is
to get rid of it again once the refactorings I'm planning are
finished.
Or rather, I'll get rid of _that_ part of its functionality. I also
suspect I'll have added new kinds of consistency check by then, which
won't be a liability in the same way, and which I'll want to keep.
2023-09-22 12:57:50 +00:00
|
|
|
void test_simple(void)
|
|
|
|
{
|
|
|
|
test_str_simple(CONF_host, "HostName", "");
|
|
|
|
test_int_translated(CONF_addressfamily, "AddressFamily", ADDRTYPE_UNSPEC,
|
|
|
|
ADDRTYPE_UNSPEC, 0, ADDRTYPE_IPV4, 1,
|
|
|
|
ADDRTYPE_IPV6, 2, -1);
|
|
|
|
test_bool_simple(CONF_warn_on_close, "WarnOnClose", true);
|
|
|
|
test_bool_simple(CONF_tcp_nodelay, "TCPNoDelay", true);
|
|
|
|
test_bool_simple(CONF_tcp_keepalives, "TCPKeepalives", false);
|
|
|
|
test_str_simple(CONF_loghost, "LogHost", "");
|
|
|
|
test_str_simple(CONF_proxy_exclude_list, "ProxyExcludeList", "");
|
|
|
|
test_bool_simple(CONF_even_proxy_localhost, "ProxyLocalhost", false);
|
|
|
|
test_str_simple(CONF_proxy_host, "ProxyHost", "proxy");
|
|
|
|
test_int_simple(CONF_proxy_port, "ProxyPort", 80);
|
|
|
|
test_str_simple(CONF_proxy_username, "ProxyUsername", "");
|
|
|
|
test_str_simple(CONF_proxy_password, "ProxyPassword", "");
|
|
|
|
test_str_simple(CONF_proxy_telnet_command, "ProxyTelnetCommand", "connect %host %port\\n");
|
|
|
|
test_int_translated(CONF_proxy_log_to_term, "ProxyLogToTerm", FORCE_OFF,
|
|
|
|
FORCE_ON, 0, FORCE_OFF, 1, AUTO, 2, -1);
|
2024-09-26 09:50:47 +00:00
|
|
|
test_str_ambi_simple(CONF_remote_cmd, "RemoteCommand", "", false);
|
New test program 'test_conf', mostly transitional.
This aims to be a reasonably exhaustive test of what happens if you
set Conf values to various things, and then save your session, and
find out what ends up in the storage. Or vice versa.
Currently, the test program is written to match the existing
behaviour. The idea is that I can refactor the code that does the
loading and saving, and if this test still passes, I've probably done
it right.
However, in the long term, this test will be a liability: it's yet
another place you have to add every new config option. So my plan is
to get rid of it again once the refactorings I'm planning are
finished.
Or rather, I'll get rid of _that_ part of its functionality. I also
suspect I'll have added new kinds of consistency check by then, which
won't be a liability in the same way, and which I'll want to keep.
2023-09-22 12:57:50 +00:00
|
|
|
test_bool_simple(CONF_nopty, "NoPTY", false);
|
|
|
|
test_bool_simple(CONF_compression, "Compression", false);
|
|
|
|
test_bool_simple(CONF_ssh_prefer_known_hostkeys, "PreferKnownHostKeys", true);
|
|
|
|
test_int_simple(CONF_ssh_rekey_time, "RekeyTime", 60);
|
|
|
|
test_str_simple(CONF_ssh_rekey_data, "RekeyBytes", "1G");
|
|
|
|
test_bool_simple(CONF_tryagent, "TryAgent", true);
|
|
|
|
test_bool_simple(CONF_agentfwd, "AgentFwd", false);
|
|
|
|
test_bool_simple(CONF_change_username, "ChangeUsername", false);
|
|
|
|
test_file_simple(CONF_keyfile, "PublicKeyFile");
|
|
|
|
test_file_simple(CONF_detached_cert, "DetachedCertificate");
|
|
|
|
test_str_simple(CONF_auth_plugin, "AuthPlugin", "");
|
|
|
|
test_bool_simple(CONF_ssh2_des_cbc, "SSH2DES", false);
|
|
|
|
test_bool_simple(CONF_ssh_no_userauth, "SshNoAuth", false);
|
|
|
|
test_bool_simple(CONF_ssh_no_trivial_userauth, "SshNoTrivialAuth", false);
|
|
|
|
test_bool_simple(CONF_ssh_show_banner, "SshBanner", true);
|
|
|
|
test_bool_simple(CONF_try_tis_auth, "AuthTIS", false);
|
|
|
|
test_bool_simple(CONF_try_ki_auth, "AuthKI", true);
|
|
|
|
test_bool_simple(CONF_ssh_no_shell, "SshNoShell", false);
|
|
|
|
test_str_simple(CONF_termtype, "TerminalType", "xterm");
|
|
|
|
test_str_simple(CONF_termspeed, "TerminalSpeed", "38400,38400");
|
2024-09-23 15:59:11 +00:00
|
|
|
test_str_ambi_simple(CONF_username, "UserName", "", false);
|
New test program 'test_conf', mostly transitional.
This aims to be a reasonably exhaustive test of what happens if you
set Conf values to various things, and then save your session, and
find out what ends up in the storage. Or vice versa.
Currently, the test program is written to match the existing
behaviour. The idea is that I can refactor the code that does the
loading and saving, and if this test still passes, I've probably done
it right.
However, in the long term, this test will be a liability: it's yet
another place you have to add every new config option. So my plan is
to get rid of it again once the refactorings I'm planning are
finished.
Or rather, I'll get rid of _that_ part of its functionality. I also
suspect I'll have added new kinds of consistency check by then, which
won't be a liability in the same way, and which I'll want to keep.
2023-09-22 12:57:50 +00:00
|
|
|
test_bool_simple(CONF_username_from_env, "UserNameFromEnvironment", false);
|
|
|
|
test_str_simple(CONF_localusername, "LocalUserName", "");
|
|
|
|
test_bool_simple(CONF_rfc_environ, "RFCEnviron", false);
|
|
|
|
test_bool_simple(CONF_passive_telnet, "PassiveTelnet", false);
|
|
|
|
test_str_simple(CONF_serline, "SerialLine", "");
|
|
|
|
test_int_simple(CONF_serspeed, "SerialSpeed", 9600);
|
|
|
|
test_int_simple(CONF_serdatabits, "SerialDataBits", 8);
|
|
|
|
test_int_simple(CONF_serstopbits, "SerialStopHalfbits", 2);
|
|
|
|
test_int_translated(CONF_serparity, "SerialParity", SER_PAR_NONE,
|
|
|
|
SER_PAR_NONE, 0, SER_PAR_ODD, 1, SER_PAR_EVEN, 2,
|
|
|
|
SER_PAR_MARK, 3, SER_PAR_SPACE, 4, -1);
|
|
|
|
test_int_translated(CONF_serflow, "SerialFlowControl", SER_FLOW_XONXOFF,
|
|
|
|
SER_FLOW_NONE, 0, SER_FLOW_XONXOFF, 1,
|
|
|
|
SER_FLOW_RTSCTS, 2, SER_FLOW_DSRDTR, 3, -1);
|
|
|
|
test_str_simple(CONF_supdup_location, "SUPDUPLocation", "The Internet");
|
|
|
|
test_int_translated(CONF_supdup_ascii_set, "SUPDUPCharset",
|
|
|
|
SUPDUP_CHARSET_ASCII,
|
|
|
|
SUPDUP_CHARSET_ASCII, 0,
|
|
|
|
SUPDUP_CHARSET_ITS, 1,
|
|
|
|
SUPDUP_CHARSET_WAITS, 2, -1);
|
|
|
|
test_bool_simple(CONF_supdup_more, "SUPDUPMoreProcessing", false);
|
|
|
|
test_bool_simple(CONF_supdup_scroll, "SUPDUPScrolling", false);
|
|
|
|
test_bool_simple(CONF_bksp_is_delete, "BackspaceIsDelete", true);
|
|
|
|
test_bool_simple(CONF_rxvt_homeend, "RXVTHomeEnd", false);
|
|
|
|
test_int_translated(CONF_funky_type, "LinuxFunctionKeys", FUNKY_TILDE,
|
|
|
|
FUNKY_TILDE, 0, FUNKY_LINUX, 1, FUNKY_XTERM, 2,
|
|
|
|
FUNKY_VT400, 3, FUNKY_VT100P, 4, FUNKY_SCO, 5,
|
|
|
|
FUNKY_XTERM_216, 6, -1);
|
|
|
|
test_int_translated(CONF_sharrow_type, "ShiftedArrowKeys",
|
|
|
|
SHARROW_APPLICATION,
|
|
|
|
SHARROW_APPLICATION, 0, SHARROW_BITMAP, 1, -1);
|
|
|
|
test_bool_simple(CONF_no_applic_c, "NoApplicationCursors", false);
|
|
|
|
test_bool_simple(CONF_no_applic_k, "NoApplicationKeys", false);
|
|
|
|
test_bool_simple(CONF_no_mouse_rep, "NoMouseReporting", false);
|
|
|
|
test_bool_simple(CONF_no_remote_resize, "NoRemoteResize", false);
|
|
|
|
test_bool_simple(CONF_no_alt_screen, "NoAltScreen", false);
|
|
|
|
test_bool_simple(CONF_no_remote_wintitle, "NoRemoteWinTitle", false);
|
|
|
|
test_bool_simple(CONF_no_remote_clearscroll, "NoRemoteClearScroll", false);
|
|
|
|
test_bool_simple(CONF_no_dbackspace, "NoDBackspace", false);
|
|
|
|
test_bool_simple(CONF_no_remote_charset, "NoRemoteCharset", false);
|
|
|
|
/* note we have no test for CONF_remote_qtitle_action because no default */
|
|
|
|
test_bool_simple(CONF_app_cursor, "ApplicationCursorKeys", false);
|
|
|
|
test_bool_simple(CONF_app_keypad, "ApplicationKeypad", false);
|
|
|
|
test_bool_simple(CONF_nethack_keypad, "NetHackKeypad", false);
|
|
|
|
test_bool_simple(CONF_telnet_keyboard, "TelnetKey", false);
|
|
|
|
test_bool_simple(CONF_telnet_newline, "TelnetRet", true);
|
|
|
|
test_bool_simple(CONF_alt_f4, "AltF4", true);
|
|
|
|
test_bool_simple(CONF_alt_space, "AltSpace", false);
|
|
|
|
test_bool_simple(CONF_alt_only, "AltOnly", false);
|
|
|
|
test_int_translated(CONF_localecho, "LocalEcho", AUTO,
|
|
|
|
FORCE_ON, 0, FORCE_OFF, 1, AUTO, 2, -1);
|
|
|
|
test_int_translated(CONF_localedit, "LocalEdit", AUTO,
|
|
|
|
FORCE_ON, 0, FORCE_OFF, 1, AUTO, 2, -1);
|
|
|
|
test_bool_simple(CONF_alwaysontop, "AlwaysOnTop", false);
|
|
|
|
test_bool_simple(CONF_fullscreenonaltenter, "FullScreenOnAltEnter", false);
|
|
|
|
test_bool_simple(CONF_scroll_on_key, "ScrollOnKey", false);
|
|
|
|
test_bool_simple(CONF_scroll_on_disp, "ScrollOnDisp", true);
|
|
|
|
test_bool_simple(CONF_erase_to_scrollback, "EraseToScrollback", true);
|
|
|
|
test_bool_simple(CONF_compose_key, "ComposeKey", false);
|
|
|
|
test_bool_simple(CONF_ctrlaltkeys, "CtrlAltKeys", true);
|
|
|
|
test_str_simple(CONF_wintitle, "WinTitle", "");
|
|
|
|
test_int_simple(CONF_savelines, "ScrollbackLines", 2000);
|
|
|
|
test_bool_simple(CONF_dec_om, "DECOriginMode", false);
|
|
|
|
test_bool_simple(CONF_wrap_mode, "AutoWrapMode", true);
|
|
|
|
test_bool_simple(CONF_lfhascr, "LFImpliesCR", false);
|
|
|
|
test_int_translated(CONF_cursor_type, "CurType", CURSOR_BLOCK,
|
|
|
|
CURSOR_BLOCK, 0, CURSOR_UNDERLINE, 1,
|
|
|
|
CURSOR_VERTICAL_LINE, 2, -1);
|
|
|
|
test_bool_simple(CONF_blink_cur, "BlinkCur", false);
|
|
|
|
test_int_translated(CONF_beep, "Beep", 1,
|
|
|
|
BELL_DISABLED, 0, BELL_DEFAULT, 1, BELL_VISUAL, 2,
|
|
|
|
BELL_WAVEFILE, 3, BELL_PCSPEAKER, 4, -1);
|
|
|
|
test_int_translated(CONF_beep_ind, "BeepInd", 0,
|
|
|
|
B_IND_DISABLED, 0, B_IND_FLASH, 1, B_IND_STEADY, 2, -1);
|
|
|
|
test_bool_simple(CONF_bellovl, "BellOverload", true);
|
|
|
|
test_int_simple(CONF_bellovl_n, "BellOverloadN", 5);
|
|
|
|
test_file_simple(CONF_bell_wavefile, "BellWaveFile");
|
|
|
|
test_bool_simple(CONF_scrollbar, "ScrollBar", true);
|
|
|
|
test_bool_simple(CONF_scrollbar_in_fullscreen, "ScrollBarFullScreen", false);
|
|
|
|
test_int_translated(CONF_resize_action, "LockSize", RESIZE_TERM,
|
|
|
|
RESIZE_TERM, 0, RESIZE_DISABLED, 1, RESIZE_FONT, 2,
|
|
|
|
RESIZE_EITHER, 3, -1);
|
|
|
|
test_bool_simple(CONF_bce, "BCE", true);
|
|
|
|
test_bool_simple(CONF_blinktext, "BlinkText", false);
|
|
|
|
test_bool_simple(CONF_win_name_always, "WinNameAlways", true);
|
|
|
|
test_int_simple(CONF_width, "TermWidth", 80);
|
|
|
|
test_int_simple(CONF_height, "TermHeight", 24);
|
|
|
|
test_font_simple(CONF_font, "Font");
|
|
|
|
test_int_translated(CONF_font_quality, "FontQuality", FQ_DEFAULT,
|
|
|
|
FQ_DEFAULT, 0, FQ_ANTIALIASED, 1, FQ_NONANTIALIASED, 2,
|
|
|
|
FQ_CLEARTYPE, 3, -1);
|
|
|
|
test_file_simple(CONF_logfilename, "LogFileName");
|
|
|
|
test_int_translated(CONF_logtype, "LogType", LGTYP_NONE,
|
|
|
|
LGTYP_NONE, 0, LGTYP_ASCII, 1, LGTYP_DEBUG, 2,
|
|
|
|
LGTYP_PACKETS, 3, LGTYP_SSHRAW, 4, -1);
|
|
|
|
/* FIXME: this won't work because -1 is also the terminator, darn */
|
|
|
|
test_int_translated(CONF_logxfovr, "LogFileClash", LGXF_ASK,
|
|
|
|
LGXF_OVR, 1, LGXF_APN, 0, LGXF_ASK, -1, -1);
|
|
|
|
test_bool_simple(CONF_logflush, "LogFlush", true);
|
|
|
|
test_bool_simple(CONF_logheader, "LogHeader", true);
|
|
|
|
test_bool_simple(CONF_logomitpass, "SSHLogOmitPasswords", true);
|
|
|
|
test_bool_simple(CONF_logomitdata, "SSHLogOmitData", false);
|
|
|
|
test_bool_simple(CONF_hide_mouseptr, "HideMousePtr", false);
|
|
|
|
test_bool_simple(CONF_sunken_edge, "SunkenEdge", false);
|
|
|
|
test_int_simple(CONF_window_border, "WindowBorder", 1);
|
|
|
|
test_str_simple(CONF_answerback, "Answerback", "PuTTY");
|
|
|
|
test_str_simple(CONF_printer, "Printer", "");
|
|
|
|
test_bool_simple(CONF_no_arabicshaping, "DisableArabicShaping", false);
|
|
|
|
test_bool_simple(CONF_no_bidi, "DisableBidi", false);
|
|
|
|
test_bool_simple(CONF_ansi_colour, "ANSIColour", true);
|
|
|
|
test_bool_simple(CONF_xterm_256_colour, "Xterm256Colour", true);
|
|
|
|
test_bool_simple(CONF_true_colour, "TrueColour", true);
|
|
|
|
test_bool_simple(CONF_system_colour, "UseSystemColours", false);
|
|
|
|
test_bool_simple(CONF_try_palette, "TryPalette", false);
|
|
|
|
test_int_translated(CONF_mouse_is_xterm, "MouseIsXterm", 0,
|
|
|
|
MOUSE_COMPROMISE, 0, MOUSE_XTERM, 1,
|
|
|
|
MOUSE_WINDOWS, 2, -1);
|
|
|
|
test_bool_simple(CONF_rect_select, "RectSelect", false);
|
|
|
|
test_bool_simple(CONF_paste_controls, "PasteControls", false);
|
|
|
|
test_bool_simple(CONF_rawcnp, "RawCNP", false);
|
|
|
|
test_bool_simple(CONF_utf8linedraw, "UTF8linedraw", false);
|
|
|
|
test_bool_simple(CONF_rtf_paste, "PasteRTF", false);
|
|
|
|
test_bool_simple(CONF_mouse_override, "MouseOverride", true);
|
|
|
|
test_bool_simple(CONF_mouseautocopy, "MouseAutocopy", CLIPUI_DEFAULT_AUTOCOPY);
|
|
|
|
test_int_translated(CONF_vtmode, "FontVTMode", VT_UNICODE,
|
|
|
|
VT_XWINDOWS, 0,
|
|
|
|
VT_OEMANSI, 1,
|
|
|
|
VT_OEMONLY, 2,
|
|
|
|
VT_POORMAN, 3,
|
|
|
|
VT_UNICODE, 4,
|
|
|
|
-1);
|
|
|
|
test_str_simple(CONF_line_codepage, "LineCodePage", "");
|
|
|
|
test_bool_simple(CONF_cjk_ambig_wide, "CJKAmbigWide", false);
|
|
|
|
test_bool_simple(CONF_utf8_override, "UTF8Override", true);
|
|
|
|
test_bool_simple(CONF_xlat_capslockcyr, "CapsLockCyr", false);
|
|
|
|
test_bool_simple(CONF_x11_forward, "X11Forward", false);
|
|
|
|
test_str_simple(CONF_x11_display, "X11Display", "");
|
|
|
|
test_int_translated(CONF_x11_auth, "X11AuthType", X11_MIT,
|
|
|
|
X11_NO_AUTH, 0, X11_MIT, 1, X11_XDM, 2, -1);
|
|
|
|
test_file_simple(CONF_xauthfile, "X11AuthFile");
|
|
|
|
test_bool_simple(CONF_lport_acceptall, "LocalPortAcceptAll", false);
|
|
|
|
test_bool_simple(CONF_rport_acceptall, "RemotePortAcceptAll", false);
|
|
|
|
test_bool_simple(CONF_ssh_connection_sharing, "ConnectionSharing", false);
|
|
|
|
test_bool_simple(CONF_ssh_connection_sharing_upstream, "ConnectionSharingUpstream", true);
|
|
|
|
test_bool_simple(CONF_ssh_connection_sharing_downstream, "ConnectionSharingDownstream", true);
|
|
|
|
test_bool_simple(CONF_stamp_utmp, "StampUtmp", true);
|
|
|
|
test_bool_simple(CONF_login_shell, "LoginShell", true);
|
|
|
|
test_bool_simple(CONF_scrollbar_on_left, "ScrollbarOnLeft", false);
|
|
|
|
test_bool_simple(CONF_shadowbold, "ShadowBold", false);
|
|
|
|
test_font_simple(CONF_boldfont, "BoldFont");
|
|
|
|
test_font_simple(CONF_widefont, "WideFont");
|
|
|
|
test_font_simple(CONF_wideboldfont, "WideBoldFont");
|
|
|
|
test_int_simple(CONF_shadowboldoffset, "ShadowBoldOffset", 1);
|
|
|
|
test_bool_simple(CONF_crhaslf, "CRImpliesLF", false);
|
|
|
|
test_str_simple(CONF_winclass, "WindowClass", "");
|
|
|
|
test_int_translated(CONF_close_on_exit, "CloseOnExit", AUTO,
|
|
|
|
FORCE_OFF, 0, AUTO, 1, FORCE_ON, 2, -1);
|
|
|
|
test_int_translated(CONF_proxy_dns, "ProxyDNS", AUTO,
|
|
|
|
FORCE_OFF, 0, AUTO, 1, FORCE_ON, 2, -1);
|
|
|
|
test_int_translated(CONF_bold_style, "BoldAsColour", AUTO,
|
|
|
|
1, 0, 2, 1, 3, 2, -1);
|
|
|
|
test_int_translated(CONF_sshbug_ignore1, "BugIgnore1", AUTO,
|
|
|
|
AUTO, 0, FORCE_OFF, 1, FORCE_ON, 2, -1);
|
|
|
|
test_int_translated(CONF_sshbug_plainpw1, "BugPlainPW1", AUTO,
|
|
|
|
AUTO, 0, FORCE_OFF, 1, FORCE_ON, 2, -1);
|
|
|
|
test_int_translated(CONF_sshbug_rsa1, "BugRSA1", AUTO,
|
|
|
|
AUTO, 0, FORCE_OFF, 1, FORCE_ON, 2, -1);
|
|
|
|
test_int_translated(CONF_sshbug_ignore2, "BugIgnore2", AUTO,
|
|
|
|
AUTO, 0, FORCE_OFF, 1, FORCE_ON, 2, -1);
|
|
|
|
test_int_translated(CONF_sshbug_derivekey2, "BugDeriveKey2", AUTO,
|
|
|
|
AUTO, 0, FORCE_OFF, 1, FORCE_ON, 2, -1);
|
|
|
|
test_int_translated(CONF_sshbug_rsapad2, "BugRSAPad2", AUTO,
|
|
|
|
AUTO, 0, FORCE_OFF, 1, FORCE_ON, 2, -1);
|
|
|
|
test_int_translated(CONF_sshbug_pksessid2, "BugPKSessID2", AUTO,
|
|
|
|
AUTO, 0, FORCE_OFF, 1, FORCE_ON, 2, -1);
|
|
|
|
test_int_translated(CONF_sshbug_rekey2, "BugRekey2", AUTO,
|
|
|
|
AUTO, 0, FORCE_OFF, 1, FORCE_ON, 2, -1);
|
|
|
|
test_int_translated(CONF_sshbug_maxpkt2, "BugMaxPkt2", AUTO,
|
|
|
|
AUTO, 0, FORCE_OFF, 1, FORCE_ON, 2, -1);
|
|
|
|
test_int_translated(CONF_sshbug_oldgex2, "BugOldGex2", AUTO,
|
|
|
|
AUTO, 0, FORCE_OFF, 1, FORCE_ON, 2, -1);
|
|
|
|
test_int_translated(CONF_sshbug_winadj, "BugWinadj", AUTO,
|
|
|
|
AUTO, 0, FORCE_OFF, 1, FORCE_ON, 2, -1);
|
|
|
|
test_int_translated(CONF_sshbug_chanreq, "BugChanReq", AUTO,
|
|
|
|
AUTO, 0, FORCE_OFF, 1, FORCE_ON, 2, -1);
|
|
|
|
test_int_translated(CONF_sshbug_dropstart, "BugDropStart", FORCE_OFF,
|
|
|
|
FORCE_OFF, 1, FORCE_ON, 2, -1);
|
|
|
|
test_int_translated(CONF_sshbug_filter_kexinit, "BugFilterKexinit", FORCE_OFF,
|
|
|
|
FORCE_OFF, 1, FORCE_ON, 2, -1);
|
|
|
|
test_int_translated(CONF_sshbug_rsa_sha2_cert_userauth, "BugRSASHA2CertUserauth", AUTO,
|
|
|
|
AUTO, 0, FORCE_OFF, 1, FORCE_ON, 2, -1);
|
Add ability to specify custom load and save separately.
This allows a couple more settings to be treated automatically on
save, which are more complicated on load because they still honour
older alternative save keywords.
In particular, CONF_proxy_type and CONF_remote_qtitle_action now have
explicit enum mappings. These were needed for the automated save code,
but also, I've rewritten the custom load code to use them too. This
decouples the storage format of those settings from the order of
values in the internal enum, which is generally an advantage of
specifying storage enums explicitly.
Those two settings weren't already tested by test_conf, because I
wasn't changing them in previous commits. Now I've added extra code
that does test them, and verified it works when backported to commit
b567c9b2b5e159f where I introduced test_conf before beginning the main
refactoring.
A setting can also be specified explicitly as not loaded and saved at
all. There were quite a few commented that way, but now there's a
machine-readable indication of it.
test_conf will now check that all these settings make sense together -
things shouldn't have a save keyword unless they use it, and should
have one if they don't, and shouldn't specify combinations of options
that conflict.
(For that reason, test_conf is now also running the consistency check
before the main test, so that a missing keyword will cause an error
message _before_ it causes a segfault, saving some debugging!)
2023-09-22 15:04:25 +00:00
|
|
|
test_int_translated(CONF_proxy_type, "ProxyMethod", PROXY_NONE,
|
|
|
|
PROXY_NONE, 0, PROXY_SOCKS4, 1, PROXY_SOCKS5, 2,
|
|
|
|
PROXY_HTTP, 3, PROXY_TELNET, 4, PROXY_CMD, 5,
|
|
|
|
PROXY_SSH_TCPIP, 6, PROXY_SSH_EXEC, 7,
|
|
|
|
PROXY_SSH_SUBSYSTEM, 8, -1);
|
|
|
|
test_int_translated_load_legacy(
|
|
|
|
CONF_proxy_type, "ProxyType", NULL, PROXY_NONE,
|
|
|
|
PROXY_HTTP, 1, PROXY_SOCKS5, 2, PROXY_TELNET, 3, PROXY_CMD, 4, -1);
|
|
|
|
test_int_translated_load_legacy(
|
|
|
|
CONF_proxy_type, "ProxyType", load_prepare_socks4, PROXY_NONE,
|
|
|
|
PROXY_HTTP, 1, PROXY_SOCKS4, 2, PROXY_TELNET, 3, PROXY_CMD, 4, -1);
|
|
|
|
test_int_translated(CONF_remote_qtitle_action, "RemoteQTitleAction", TITLE_EMPTY,
|
|
|
|
TITLE_NONE, 0, TITLE_EMPTY, 1, TITLE_REAL, 2, -1);
|
|
|
|
test_int_translated_load_legacy(
|
|
|
|
CONF_remote_qtitle_action, "NoRemoteQTitle", NULL, TITLE_EMPTY,
|
|
|
|
TITLE_REAL, 0, TITLE_EMPTY, 1, -1);
|
New test program 'test_conf', mostly transitional.
This aims to be a reasonably exhaustive test of what happens if you
set Conf values to various things, and then save your session, and
find out what ends up in the storage. Or vice versa.
Currently, the test program is written to match the existing
behaviour. The idea is that I can refactor the code that does the
loading and saving, and if this test still passes, I've probably done
it right.
However, in the long term, this test will be a liability: it's yet
another place you have to add every new config option. So my plan is
to get rid of it again once the refactorings I'm planning are
finished.
Or rather, I'll get rid of _that_ part of its functionality. I also
suspect I'll have added new kinds of consistency check by then, which
won't be a liability in the same way, and which I'll want to keep.
2023-09-22 12:57:50 +00:00
|
|
|
}
|
|
|
|
|
2023-09-22 14:33:45 +00:00
|
|
|
void test_conf_key_info(void)
|
|
|
|
{
|
|
|
|
struct test_data {
|
|
|
|
const char *name;
|
|
|
|
bool got_value_type : 1;
|
|
|
|
bool got_subkey_type : 1;
|
2023-09-22 15:30:24 +00:00
|
|
|
bool got_default : 1;
|
2023-09-22 14:33:45 +00:00
|
|
|
bool got_default_int : 1;
|
|
|
|
bool got_default_str : 1;
|
|
|
|
bool got_default_bool : 1;
|
|
|
|
bool got_save_keyword : 1;
|
|
|
|
bool got_storage_enum : 1;
|
Add ability to specify custom load and save separately.
This allows a couple more settings to be treated automatically on
save, which are more complicated on load because they still honour
older alternative save keywords.
In particular, CONF_proxy_type and CONF_remote_qtitle_action now have
explicit enum mappings. These were needed for the automated save code,
but also, I've rewritten the custom load code to use them too. This
decouples the storage format of those settings from the order of
values in the internal enum, which is generally an advantage of
specifying storage enums explicitly.
Those two settings weren't already tested by test_conf, because I
wasn't changing them in previous commits. Now I've added extra code
that does test them, and verified it works when backported to commit
b567c9b2b5e159f where I introduced test_conf before beginning the main
refactoring.
A setting can also be specified explicitly as not loaded and saved at
all. There were quite a few commented that way, but now there's a
machine-readable indication of it.
test_conf will now check that all these settings make sense together -
things shouldn't have a save keyword unless they use it, and should
have one if they don't, and shouldn't specify combinations of options
that conflict.
(For that reason, test_conf is now also running the consistency check
before the main test, so that a missing keyword will cause an error
message _before_ it causes a segfault, saving some debugging!)
2023-09-22 15:04:25 +00:00
|
|
|
bool save_custom : 1;
|
|
|
|
bool load_custom : 1;
|
|
|
|
bool not_saved : 1;
|
2023-09-22 14:33:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#define CONF_OPTION(id, ...) { .name = "CONF_" #id, __VA_ARGS__ },
|
|
|
|
#define VALUE_TYPE(x) .got_value_type = true
|
|
|
|
#define SUBKEY_TYPE(x) .got_subkey_type = true
|
2023-09-22 15:30:24 +00:00
|
|
|
#define DEFAULT_INT(x) .got_default_int = true, .got_default = true
|
|
|
|
#define DEFAULT_STR(x) .got_default_str = true, .got_default = true
|
|
|
|
#define DEFAULT_BOOL(x) .got_default_bool = true, .got_default = true
|
2023-09-22 14:33:45 +00:00
|
|
|
#define SAVE_KEYWORD(x) .got_save_keyword = true
|
|
|
|
#define STORAGE_ENUM(x) .got_storage_enum = true
|
Add ability to specify custom load and save separately.
This allows a couple more settings to be treated automatically on
save, which are more complicated on load because they still honour
older alternative save keywords.
In particular, CONF_proxy_type and CONF_remote_qtitle_action now have
explicit enum mappings. These were needed for the automated save code,
but also, I've rewritten the custom load code to use them too. This
decouples the storage format of those settings from the order of
values in the internal enum, which is generally an advantage of
specifying storage enums explicitly.
Those two settings weren't already tested by test_conf, because I
wasn't changing them in previous commits. Now I've added extra code
that does test them, and verified it works when backported to commit
b567c9b2b5e159f where I introduced test_conf before beginning the main
refactoring.
A setting can also be specified explicitly as not loaded and saved at
all. There were quite a few commented that way, but now there's a
machine-readable indication of it.
test_conf will now check that all these settings make sense together -
things shouldn't have a save keyword unless they use it, and should
have one if they don't, and shouldn't specify combinations of options
that conflict.
(For that reason, test_conf is now also running the consistency check
before the main test, so that a missing keyword will cause an error
message _before_ it causes a segfault, saving some debugging!)
2023-09-22 15:04:25 +00:00
|
|
|
#define SAVE_CUSTOM .save_custom = true
|
|
|
|
#define LOAD_CUSTOM .load_custom = true
|
|
|
|
#define NOT_SAVED .not_saved = true
|
2023-09-22 14:33:45 +00:00
|
|
|
|
|
|
|
static const struct test_data conf_key_test_data[] = {
|
|
|
|
#include "conf.h"
|
|
|
|
};
|
|
|
|
|
|
|
|
for (size_t key = 0; key < N_CONFIG_OPTIONS; key++) {
|
|
|
|
const ConfKeyInfo *info = &conf_key_info[key];
|
|
|
|
const struct test_data *td = &conf_key_test_data[key];
|
|
|
|
|
|
|
|
if (!td->got_value_type) {
|
|
|
|
fprintf(stderr, "%s: no value type\n", td->name);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
2023-09-22 15:30:24 +00:00
|
|
|
if (td->got_default && info->subkey_type != CONF_TYPE_NONE) {
|
|
|
|
fprintf(stderr, "%s: is a mapping but has a default\n", td->name);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
2023-09-22 14:33:45 +00:00
|
|
|
if ((td->got_default_int && info->value_type != CONF_TYPE_INT) ||
|
Add two new string types to the Conf system.
This begins the process of making PuTTY more able to handle Unicode
strings as a first-class type in its configuration. One of the new
types, CONF_TYPE_UTF8, looks physically just like CONF_TYPE_STR but
the semantics are that it's definitely encoded in UTF-8, instead of
'shrug, whatever the system locale's encoding is'.
Unfortunately, we can't yet switch over any Conf items to having that
type, because our data representations in saved configuration (both on
Unix and Windows) store char strings in the system encoding. So we'll
have to change that representation at the same time, which risks
breaking backwards compatibility with old PuTTYs reading the same
configuration.
So the other new type, CONF_TYPE_STR_AMBI, is intended as a
transitional form, recording a configuration setting that _might_ be
explicitly UTF-8 or might have the legacy 'shrug, whatever' semantics,
depending on where we got it from.
My general migration plan is that first I _enable_ Unicode support in
a Conf item, by turning it into STR_AMBI; the Unicode version of the
string (if any) is saved in a new location, and a best-effort
local-charset version is saved where it's always been. That way new
PuTTY can read the Unicode version, and old PuTTY reading that
configuration will behave no worse than it would have done already.
It would be nice to think that in the far future we've migrated
everything to STR_AMBI and can move them all to mandatory UTF-8,
obsoleting the old configuration. I think it's more likely we'll never
get there. But at least _new_ Conf items, with no backwards
compatibility requirement in the first place, can be CONF_TYPE_UTF8
where appropriate.
(In conf_get_str_ambi(), I considered making it mandatory via assert()
to pass the 'utf8' output pointer as non-NULL, to defend against lazy
adaptation of existing code by just changing the function call. But in
fact I think there's a legitimate use case for not caring if the
output is UTF-8 or not, because some of the existing SSH code
currently just shoves strings like usernames directly on to the wire
whether they're in the right encoding or not; so if you want to do the
correct UTF-8 thing where possible and preserve legacy behaviour if
not, then treating both classes of string the same _is_ the right
thing to do.)
This also requires linking the Unicode support into many Unix
applications that hadn't previously needed it.
2024-09-23 11:00:37 +00:00
|
|
|
(td->got_default_str &&
|
|
|
|
(info->value_type != CONF_TYPE_STR &&
|
|
|
|
info->value_type != CONF_TYPE_STR_AMBI &&
|
|
|
|
info->value_type != CONF_TYPE_UTF8)) ||
|
2023-09-22 14:33:45 +00:00
|
|
|
(td->got_default_bool && info->value_type != CONF_TYPE_BOOL)) {
|
|
|
|
fprintf(stderr, "%s: default doesn't match type\n", td->name);
|
|
|
|
nfails++;
|
|
|
|
}
|
Add ability to specify custom load and save separately.
This allows a couple more settings to be treated automatically on
save, which are more complicated on load because they still honour
older alternative save keywords.
In particular, CONF_proxy_type and CONF_remote_qtitle_action now have
explicit enum mappings. These were needed for the automated save code,
but also, I've rewritten the custom load code to use them too. This
decouples the storage format of those settings from the order of
values in the internal enum, which is generally an advantage of
specifying storage enums explicitly.
Those two settings weren't already tested by test_conf, because I
wasn't changing them in previous commits. Now I've added extra code
that does test them, and verified it works when backported to commit
b567c9b2b5e159f where I introduced test_conf before beginning the main
refactoring.
A setting can also be specified explicitly as not loaded and saved at
all. There were quite a few commented that way, but now there's a
machine-readable indication of it.
test_conf will now check that all these settings make sense together -
things shouldn't have a save keyword unless they use it, and should
have one if they don't, and shouldn't specify combinations of options
that conflict.
(For that reason, test_conf is now also running the consistency check
before the main test, so that a missing keyword will cause an error
message _before_ it causes a segfault, saving some debugging!)
2023-09-22 15:04:25 +00:00
|
|
|
|
|
|
|
if (td->got_storage_enum && info->value_type != CONF_TYPE_INT) {
|
|
|
|
fprintf(stderr, "%s: has STORAGE_ENUM but isn't an int\n",
|
|
|
|
td->name);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (td->not_saved) {
|
2023-09-22 15:30:24 +00:00
|
|
|
if (!td->got_default && info->subkey_type == CONF_TYPE_NONE) {
|
|
|
|
fprintf(stderr, "%s: simple unsaved setting but has no "
|
|
|
|
"default\n", td->name);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
Add ability to specify custom load and save separately.
This allows a couple more settings to be treated automatically on
save, which are more complicated on load because they still honour
older alternative save keywords.
In particular, CONF_proxy_type and CONF_remote_qtitle_action now have
explicit enum mappings. These were needed for the automated save code,
but also, I've rewritten the custom load code to use them too. This
decouples the storage format of those settings from the order of
values in the internal enum, which is generally an advantage of
specifying storage enums explicitly.
Those two settings weren't already tested by test_conf, because I
wasn't changing them in previous commits. Now I've added extra code
that does test them, and verified it works when backported to commit
b567c9b2b5e159f where I introduced test_conf before beginning the main
refactoring.
A setting can also be specified explicitly as not loaded and saved at
all. There were quite a few commented that way, but now there's a
machine-readable indication of it.
test_conf will now check that all these settings make sense together -
things shouldn't have a save keyword unless they use it, and should
have one if they don't, and shouldn't specify combinations of options
that conflict.
(For that reason, test_conf is now also running the consistency check
before the main test, so that a missing keyword will cause an error
message _before_ it causes a segfault, saving some debugging!)
2023-09-22 15:04:25 +00:00
|
|
|
if (td->got_save_keyword) {
|
|
|
|
fprintf(stderr, "%s: not saved but has SAVE_KEYWORD\n",
|
|
|
|
td->name);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (td->save_custom) {
|
|
|
|
fprintf(stderr, "%s: not saved but has SAVE_CUSTOM\n",
|
|
|
|
td->name);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (td->load_custom) {
|
|
|
|
fprintf(stderr, "%s: not saved but has LOAD_CUSTOM\n",
|
|
|
|
td->name);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (td->got_storage_enum) {
|
|
|
|
fprintf(stderr, "%s: not saved but has STORAGE_ENUM\n",
|
|
|
|
td->name);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
if (td->load_custom && td->save_custom) {
|
|
|
|
if (td->got_save_keyword) {
|
|
|
|
fprintf(stderr, "%s: no automatic save or load but has "
|
|
|
|
"SAVE_KEYWORD\n", td->name);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (td->got_storage_enum) {
|
|
|
|
fprintf(stderr, "%s: no automatic save or load but has "
|
|
|
|
"STORAGE_ENUM\n", td->name);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!td->got_save_keyword) {
|
|
|
|
fprintf(stderr, "%s: missing SAVE_KEYWORD\n", td->name);
|
|
|
|
nfails++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-09-22 14:33:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
New test program 'test_conf', mostly transitional.
This aims to be a reasonably exhaustive test of what happens if you
set Conf values to various things, and then save your session, and
find out what ends up in the storage. Or vice versa.
Currently, the test program is written to match the existing
behaviour. The idea is that I can refactor the code that does the
loading and saving, and if this test still passes, I've probably done
it right.
However, in the long term, this test will be a liability: it's yet
another place you have to add every new config option. So my plan is
to get rid of it again once the refactorings I'm planning are
finished.
Or rather, I'll get rid of _that_ part of its functionality. I also
suspect I'll have added new kinds of consistency check by then, which
won't be a liability in the same way, and which I'll want to keep.
2023-09-22 12:57:50 +00:00
|
|
|
int main(void)
|
|
|
|
{
|
2023-09-22 14:33:45 +00:00
|
|
|
test_conf_key_info();
|
Add ability to specify custom load and save separately.
This allows a couple more settings to be treated automatically on
save, which are more complicated on load because they still honour
older alternative save keywords.
In particular, CONF_proxy_type and CONF_remote_qtitle_action now have
explicit enum mappings. These were needed for the automated save code,
but also, I've rewritten the custom load code to use them too. This
decouples the storage format of those settings from the order of
values in the internal enum, which is generally an advantage of
specifying storage enums explicitly.
Those two settings weren't already tested by test_conf, because I
wasn't changing them in previous commits. Now I've added extra code
that does test them, and verified it works when backported to commit
b567c9b2b5e159f where I introduced test_conf before beginning the main
refactoring.
A setting can also be specified explicitly as not loaded and saved at
all. There were quite a few commented that way, but now there's a
machine-readable indication of it.
test_conf will now check that all these settings make sense together -
things shouldn't have a save keyword unless they use it, and should
have one if they don't, and shouldn't specify combinations of options
that conflict.
(For that reason, test_conf is now also running the consistency check
before the main test, so that a missing keyword will cause an error
message _before_ it causes a segfault, saving some debugging!)
2023-09-22 15:04:25 +00:00
|
|
|
test_simple();
|
2023-09-22 14:15:11 +00:00
|
|
|
return nfails != 0;
|
New test program 'test_conf', mostly transitional.
This aims to be a reasonably exhaustive test of what happens if you
set Conf values to various things, and then save your session, and
find out what ends up in the storage. Or vice versa.
Currently, the test program is written to match the existing
behaviour. The idea is that I can refactor the code that does the
loading and saving, and if this test still passes, I've probably done
it right.
However, in the long term, this test will be a liability: it's yet
another place you have to add every new config option. So my plan is
to get rid of it again once the refactorings I'm planning are
finished.
Or rather, I'll get rid of _that_ part of its functionality. I also
suspect I'll have added new kinds of consistency check by then, which
won't be a liability in the same way, and which I'll want to keep.
2023-09-22 12:57:50 +00:00
|
|
|
}
|