]> granicus.if.org Git - nethack/commitdiff
Add lua tests for config file parsing
authorPasi Kallinen <paxed@alt.org>
Wed, 10 Feb 2021 17:15:35 +0000 (19:15 +0200)
committerPasi Kallinen <paxed@alt.org>
Wed, 10 Feb 2021 17:22:16 +0000 (19:22 +0200)
Bare-bones for now, more tests needed.

doc/lua.adoc
include/extern.h
src/files.c
src/nhlua.c
test/test_cnf.lua [new file with mode: 0644]

index fe650d45ac2e970847f381f25be956b81708bc1c..a6d41a3402ce95ec5c389552f6e433ed1bac1d02 100644 (file)
@@ -171,12 +171,23 @@ Example:
 === parse_config
 
 Parse string as if it was read from a config file.
+Always call parse_config_errors afterwards to check for any parsing errors.
 
 Example:
 
  nh.parse_config("OPTIONS=color");
 
 
+=== parse_config_errors
+
+Returns any errors found when parsing a config file string with parse_config.
+
+Example:
+
+ local errors = nh.parse_config("OPTIONS=color\nOPTIONS=!color");
+ nh.pline("Line: " .. errors[1].line .. ", " .. errors[1].error);
+
+
 === pline
 
 Show the text in the message area.
index 9fe5f369debba03437de6d920e37c817e44c81f6..5a7f11447e831393702c40cef5c58871a367f29e 100644 (file)
@@ -743,6 +743,9 @@ extern void makerogueghost(void);
 
 /* ### files.c ### */
 
+#if !defined(CROSSCOMPILE) || defined(CROSSCOMPILE_TARGET)
+extern int l_get_config_errors(lua_State *);
+#endif
 extern char *fname_encode(const char *, char, char *, char *, int);
 extern char *fname_decode(char, char *, char *, int);
 extern const char *fqname(const char *, int, int);
index d6db62293a4c34625553f88e9f065c639f3e4976..c488ae93c2fed8afadb309777fa39854bdd45f43 100644 (file)
@@ -2798,6 +2798,12 @@ can_read_file(const char *filename)
 }
 #endif /* USER_SOUNDS */
 
+struct _config_error_errmsg {
+    int line_num;
+    char *errormsg;
+    struct _config_error_errmsg *next;
+};
+
 struct _config_error_frame {
     int line_num;
     int num_errors;
@@ -2810,6 +2816,7 @@ struct _config_error_frame {
 };
 
 static struct _config_error_frame *config_error_data = 0;
+static struct _config_error_errmsg *config_error_msg = 0;
 
 void
 config_error_init(boolean from_file, const char *sourcename, boolean secure)
@@ -2856,6 +2863,32 @@ config_error_nextline(const char *line)
     return TRUE;
 }
 
+int
+l_get_config_errors(lua_State *L)
+{
+    struct _config_error_errmsg *dat = config_error_msg;
+    struct _config_error_errmsg *tmp;
+    int idx = 1;
+
+    lua_newtable(L);
+
+    while (dat) {
+        lua_pushinteger(L, idx++);
+        lua_newtable(L);
+        nhl_add_table_entry_int(L, "line", dat->line_num);
+        nhl_add_table_entry_str(L, "error", dat->errormsg);
+        lua_settable(L, -3);
+        tmp = dat->next;
+        free(dat->errormsg);
+        dat->errormsg = (char *) 0;
+        free(dat);
+        dat = tmp;
+    }
+    config_error_msg = (struct _config_error_errmsg *) 0;
+
+    return 1;
+}
+
 /* varargs 'config_error_add()' moved to pline.c */
 void
 config_erradd(const char *buf)
@@ -2865,6 +2898,16 @@ config_erradd(const char *buf)
     if (!buf || !*buf)
         buf = "Unknown error";
 
+    if (iflags.in_lua) {
+        struct _config_error_errmsg *dat = (struct _config_error_errmsg *) alloc(sizeof (struct _config_error_errmsg));
+
+        dat->next = config_error_msg;
+        dat->line_num = config_error_data->line_num;
+        dat->errormsg = dupstr(buf);
+        config_error_msg = dat;
+        return;
+    }
+
     if (!config_error_data) {
         /* either very early, where pline() will use raw_print(), or
            player gave bad value when prompted by interactive 'O' command */
index e92aed64b2ea2fe34f05c8d91cc154e7181a979c..e89d9889e0ae3e0982350917058bd6ab44b7ac45 100644 (file)
@@ -830,6 +830,7 @@ static const struct luaL_Reg nhl_functions[] = {
     {"level_difficulty", nhl_level_difficulty},
     {"parse_config", nhl_parse_config},
     {"get_config", nhl_get_config},
+    {"get_config_errors", l_get_config_errors},
     {NULL, NULL}
 };
 
diff --git a/test/test_cnf.lua b/test/test_cnf.lua
new file mode 100644 (file)
index 0000000..8efdf55
--- /dev/null
@@ -0,0 +1,49 @@
+
+local configtests = {
+ { test = "OPTIONS=color",  -- config string to parse
+   result = { },  -- errors, result of parsing the config string
+   extra = function() return nh.get_config("color") == "true" end  -- optional, function that returns boolean, and false means the test failed.
+   },
+ { test = "OPTIONS=!color",
+   result = { },
+   extra = function() return nh.get_config("color") == "false" end
+   },
+ { test = "OPTIONS=!color\nOPTIONS=color",
+   result = { { line = 2, error = "boolean option specified multiple times: color" } }
+   },
+};
+
+
+function testtable(t1, t2)
+   if type(t1) ~= type(t2) then return false end
+
+   for k1, v1 in pairs(t1) do
+      if type(v1) == "table" and type(t2[k1]) == "table" then
+         if not testtable(v1, t2[k1]) then return false end
+      else
+         if v1 ~= t2[k1] then return false end
+      end
+   end
+
+   return true
+end
+
+
+
+for k, v in pairs(configtests) do
+   local cnf = configtests[k].test;
+   local err = configtests[k].result;
+   nh.parse_config(cnf);
+   local res = nh.get_config_errors();
+
+   if not testtable(err, res) then
+      error("Config: Results don't match");
+   end
+
+   if (type(configtests[k].extra) == "function") then
+      if configtests[k].extra() == "false" then
+         error("Config: Failed extra test.");
+      end
+   end
+
+end