1#include <base/str.h>
2
3#include <gtest/gtest.h>
4
5static bool IsLetter(char c)
6{
7 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
8}
9
10static bool IsValidEditorTooltip(const char *pTooltip, char *pErrorMsg, int ErrorMsgSize)
11{
12 pErrorMsg[0] = '\0';
13 char aHotkey[512];
14 aHotkey[0] = '\0';
15
16 if(pTooltip[0] == '[')
17 {
18 str_copy(dst&: aHotkey, src: pTooltip + 1);
19 const char *pHotkeyEnd = str_find(haystack: aHotkey, needle: "]");
20 if(!pHotkeyEnd)
21 {
22 str_copy(dst: pErrorMsg, src: "tooltip missing closing square bracket", dst_size: ErrorMsgSize);
23 return false;
24 }
25 aHotkey[pHotkeyEnd - aHotkey] = '\0';
26
27 for(int i = 0; aHotkey[i]; i++)
28 {
29 bool ExpectLowerCase = true;
30 if(i == 0)
31 {
32 ExpectLowerCase = false;
33 }
34 else if(!IsLetter(c: aHotkey[i - 1]))
35 {
36 // the first character of a word should be uppercase
37 ExpectLowerCase = false;
38 }
39
40 bool IsLower = aHotkey[i] >= 'a' && aHotkey[i] <= 'z';
41 bool IsUpper = aHotkey[i] >= 'A' && aHotkey[i] <= 'Z';
42
43 if(ExpectLowerCase && IsUpper)
44 {
45 str_format(buffer: pErrorMsg, buffer_size: ErrorMsgSize, format: "expected character '%c' at index %d to be lower case", aHotkey[i], i + 1);
46 return false;
47 }
48 if(!ExpectLowerCase && IsLower)
49 {
50 str_format(buffer: pErrorMsg, buffer_size: ErrorMsgSize, format: "expected character '%c' at index %d to be upper case", aHotkey[i], i + 1);
51 return false;
52 }
53 }
54 }
55
56 const char *pParenthesis = str_find(haystack: pTooltip, needle: "(");
57 if(pParenthesis)
58 {
59 const char *pHotkey = str_find_nocase(haystack: pParenthesis, needle: "ctrl");
60 if(!pHotkey)
61 pHotkey = str_find_nocase(haystack: pParenthesis, needle: "shift");
62 if(!pHotkey)
63 pHotkey = str_find_nocase(haystack: pParenthesis, needle: "home");
64
65 if(pHotkey)
66 {
67 int Offset = pHotkey - pTooltip;
68 str_format(buffer: pErrorMsg, buffer_size: ErrorMsgSize, format: "found hotkey at offset %d. Hotkeys must be defined at the start.", Offset);
69 return false;
70 }
71 }
72
73 if(!str_endswith(str: pTooltip, suffix: "."))
74 {
75 str_copy(dst: pErrorMsg, src: "tooltip has to end with a dot", dst_size: ErrorMsgSize);
76 return false;
77 }
78 return true;
79}
80
81static void AssertTooltip(const char *pTooltip)
82{
83 char aError[512];
84 EXPECT_TRUE(IsValidEditorTooltip(pTooltip, aError, sizeof(aError))) << "Invalid tooltip: " << pTooltip << "\nError: " << aError;
85}
86
87TEST(Editor, QuickActionNames)
88{
89 char aError[512];
90 EXPECT_TRUE(IsValidEditorTooltip("hello world.", aError, sizeof(aError)));
91 EXPECT_TRUE(IsValidEditorTooltip("[Ctrl+H] hello world.", aError, sizeof(aError)));
92 EXPECT_FALSE(IsValidEditorTooltip("[Ctrl+H hello world.", aError, sizeof(aError)));
93 EXPECT_FALSE(IsValidEditorTooltip("[ctrl+h] hello world.", aError, sizeof(aError)));
94 EXPECT_FALSE(IsValidEditorTooltip("hello world", aError, sizeof(aError)));
95 EXPECT_FALSE(IsValidEditorTooltip("hello world (Ctrl+H).", aError, sizeof(aError)));
96
97#define REGISTER_QUICK_ACTION(name, text, callback, disabled, active, button_color, description) AssertTooltip(description);
98#include <game/editor/quick_actions.h>
99#undef REGISTER_QUICK_ACTION
100}
101