Add test case for stack usage (#484)
diff --git a/tests/stackusage/SConscript b/tests/stackusage/SConscript
new file mode 100644
index 0000000..a0c6669
--- /dev/null
+++ b/tests/stackusage/SConscript
@@ -0,0 +1,7 @@
+# Test stack usage
+
+Import("env")
+
+env.NanopbProto(["stackusage", "stackusage.options"])
+test = env.Program(["stackusage.c", "stackusage.pb.c", "$COMMON/pb_encode.o", "$COMMON/pb_decode.o", "$COMMON/pb_common.o"])
+env.RunTest(test)
diff --git a/tests/stackusage/stackusage.c b/tests/stackusage/stackusage.c
new file mode 100644
index 0000000..6e4de06
--- /dev/null
+++ b/tests/stackusage/stackusage.c
@@ -0,0 +1,94 @@
+#include <pb_encode.h>
+#include <pb_decode.h>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include "stackusage.pb.h"
+
+static uint8_t g_msgbuf[256];
+static size_t g_msglen;
+
+/* This is a hacky way to measure actual stack usage of functions.
+ * It works by copying the stack to a global variable, and then
+ * finding the lowest location that has been modified.
+ * Currently this assumes that the platform uses a descending stack.
+ */
+#define MAX_STACK_ENTRIES 1024
+static uint32_t g_stackbuf[MAX_STACK_ENTRIES];
+static uint32_t *g_stackptr;
+
+void start_stack_measuring()
+{
+ uint32_t i = 0;
+ g_stackptr = &i - MAX_STACK_ENTRIES;
+ for (i = 0; i < MAX_STACK_ENTRIES; i++)
+ {
+ g_stackbuf[i] = g_stackptr[i];
+ }
+}
+
+int end_stack_measuring()
+{
+ uint32_t i = 0;
+ for (i = 0; i < MAX_STACK_ENTRIES; i++)
+ {
+ if (g_stackbuf[i] != g_stackptr[i])
+ {
+ return (MAX_STACK_ENTRIES - i) * sizeof(uint32_t);
+ }
+ }
+ assert(false);
+ return 0;
+}
+
+void do_encode()
+{
+ pb_ostream_t stream = pb_ostream_from_buffer(g_msgbuf, sizeof(g_msgbuf));
+ SettingsGroup msg = SettingsGroup_init_zero;
+ bool status;
+
+ msg.has_settings = true;
+ msg.settings.id = 1;
+ strcpy(msg.settings.name, "abcd");
+ msg.settings.en = true;
+ msg.settings.has_begin = true;
+ msg.settings.begin.label = 1234;
+ msg.settings.begin.properties_count = 1;
+ msg.settings.begin.properties[0].which_field = Property_DeviceA_Mode_tag;
+ msg.settings.begin.properties[0].field.DeviceA_Mode = 2;
+
+ status = pb_encode(&stream, SettingsGroup_fields, &msg);
+ g_msglen = stream.bytes_written;
+ assert(status);
+ assert(g_msglen > 10);
+}
+
+void do_decode()
+{
+ pb_istream_t stream = pb_istream_from_buffer(g_msgbuf, g_msglen);
+ SettingsGroup msg = SettingsGroup_init_zero;
+ bool status;
+
+ status = pb_decode(&stream, SettingsGroup_fields, &msg);
+ assert(status);
+ assert(msg.settings.begin.properties[0].field.DeviceA_Mode == 2);
+}
+
+int main()
+{
+ int stack_encode, stack_decode;
+
+ start_stack_measuring();
+ do_encode();
+ stack_encode = end_stack_measuring();
+
+ start_stack_measuring();
+ do_decode();
+ stack_decode = end_stack_measuring();
+
+ /* Print machine-readable to stdout and user-readable to stderr */
+ printf("%d %d\n", stack_encode, stack_decode);
+ fprintf(stderr, "Stack usage: encode %d bytes, decode %d bytes\n",
+ stack_encode, stack_decode);
+ return 0;
+}
diff --git a/tests/stackusage/stackusage.options b/tests/stackusage/stackusage.options
new file mode 100644
index 0000000..a0d5841
--- /dev/null
+++ b/tests/stackusage/stackusage.options
@@ -0,0 +1,3 @@
+* long_names : false
+SettingsGroup.Settings.name max_length : 32
+SettingsGroup.Settings.Command.properties max_count : 6
diff --git a/tests/stackusage/stackusage.proto b/tests/stackusage/stackusage.proto
new file mode 100644
index 0000000..0f0437f
--- /dev/null
+++ b/tests/stackusage/stackusage.proto
@@ -0,0 +1,45 @@
+syntax = "proto3";
+
+message Property
+{
+ enum Mode
+ {
+ INVALID = 0;
+ A = 1;
+ B = 2;
+ C = 3;
+ }
+
+ oneof field
+ {
+ Mode DeviceA_Mode = 1;
+ uint32 DeviceA_Size = 2;
+ uint32 DeviceA_Length = 3;
+
+ Mode DeviceB_Mode = 4;
+ uint32 DeviceB_Size = 5;
+ uint32 DeviceB_Length = 6;
+ }
+}
+
+message SettingsGroup
+{
+ message Settings
+ {
+ message Command
+ {
+ uint32 label = 1;
+ repeated Property properties = 2;
+ }
+
+ uint32 id = 1;
+ string name = 2;
+ uint32 flags = 3;
+ bool en = 5;
+ Command begin = 6;
+ Command end = 7;
+ }
+
+ Settings settings = 1;
+ uint32 version = 2;
+}