mirror of
https://oauth2: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@github.com/m1ngsama/TNT.git
synced 2026-06-26 05:54:38 +08:00
Split tntctl local text catalog
This commit is contained in:
parent
4175bd520f
commit
fab8b315a5
11 changed files with 187 additions and 110 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -24,4 +24,5 @@ tests/unit/test_help_text
|
||||||
tests/unit/test_manual_text
|
tests/unit/test_manual_text
|
||||||
tests/unit/test_support_text
|
tests/unit/test_support_text
|
||||||
tests/unit/test_cli_text
|
tests/unit/test_cli_text
|
||||||
|
tests/unit/test_tntctl_text
|
||||||
tests/unit/test_ratelimit
|
tests/unit/test_ratelimit
|
||||||
|
|
|
||||||
4
Makefile
4
Makefile
|
|
@ -20,12 +20,12 @@ SRC_DIR = src
|
||||||
INC_DIR = include
|
INC_DIR = include
|
||||||
OBJ_DIR = obj
|
OBJ_DIR = obj
|
||||||
|
|
||||||
SOURCES = $(filter-out $(SRC_DIR)/tntctl.c,$(wildcard $(SRC_DIR)/*.c))
|
SOURCES = $(filter-out $(SRC_DIR)/tntctl.c $(SRC_DIR)/tntctl_text.c,$(wildcard $(SRC_DIR)/*.c))
|
||||||
OBJECTS = $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
|
OBJECTS = $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
|
||||||
DEPS = $(OBJECTS:.o=.d) $(CTL_OBJECTS:.o=.d)
|
DEPS = $(OBJECTS:.o=.d) $(CTL_OBJECTS:.o=.d)
|
||||||
TARGET = tnt
|
TARGET = tnt
|
||||||
CTL_TARGET = tntctl
|
CTL_TARGET = tntctl
|
||||||
CTL_OBJECTS = $(OBJ_DIR)/tntctl.o $(OBJ_DIR)/exec_catalog.o $(OBJ_DIR)/common.o $(OBJ_DIR)/i18n.o
|
CTL_OBJECTS = $(OBJ_DIR)/tntctl.o $(OBJ_DIR)/tntctl_text.o $(OBJ_DIR)/exec_catalog.o $(OBJ_DIR)/common.o $(OBJ_DIR)/i18n.o
|
||||||
TARGETS = $(TARGET) $(CTL_TARGET)
|
TARGETS = $(TARGET) $(CTL_TARGET)
|
||||||
|
|
||||||
PREFIX ?= /usr/local
|
PREFIX ?= /usr/local
|
||||||
|
|
|
||||||
|
|
@ -324,6 +324,7 @@ TNT/
|
||||||
│ ├── exec_catalog.c # SSH exec command matching, usage, and argument shape
|
│ ├── exec_catalog.c # SSH exec command matching, usage, and argument shape
|
||||||
│ ├── exec.c # SSH exec command dispatch
|
│ ├── exec.c # SSH exec command dispatch
|
||||||
│ ├── tntctl.c # local wrapper around the SSH exec interface
|
│ ├── tntctl.c # local wrapper around the SSH exec interface
|
||||||
|
│ ├── tntctl_text.c # tntctl help and option text
|
||||||
│ ├── ssh_server.c # SSH server implementation
|
│ ├── ssh_server.c # SSH server implementation
|
||||||
│ ├── bootstrap.c # SSH authentication and session bootstrap
|
│ ├── bootstrap.c # SSH authentication and session bootstrap
|
||||||
│ ├── chat_room.c # chat room logic
|
│ ├── chat_room.c # chat room logic
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
- Added a dedicated `tntctl_text` module with unit coverage for local
|
||||||
|
`tntctl` help and validation diagnostics.
|
||||||
- Documented the stable SSH exec interface contract, including exit statuses
|
- Documented the stable SSH exec interface contract, including exit statuses
|
||||||
and JSON field shapes for package tests, scripts, and future `tntctl` work.
|
and JSON field shapes for package tests, scripts, and future `tntctl` work.
|
||||||
- Documented `messages.log` v1 as the stable TNT 1.x persisted history format,
|
- Documented `messages.log` v1 as the stable TNT 1.x persisted history format,
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ make check
|
||||||
```
|
```
|
||||||
main.c → entry point, signal handling
|
main.c → entry point, signal handling
|
||||||
cli_text.c → startup CLI text
|
cli_text.c → startup CLI text
|
||||||
|
tntctl_text.c → tntctl local help and diagnostics
|
||||||
command_catalog.c → COMMAND-mode command metadata, usage, and argument shape
|
command_catalog.c → COMMAND-mode command metadata, usage, and argument shape
|
||||||
commands.c → COMMAND-mode command dispatch
|
commands.c → COMMAND-mode command dispatch
|
||||||
exec_catalog.c → SSH exec command matching, usage, and argument shape
|
exec_catalog.c → SSH exec command matching, usage, and argument shape
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ MAINTENANCE
|
||||||
STRUCTURE
|
STRUCTURE
|
||||||
src/main.c entry, signals
|
src/main.c entry, signals
|
||||||
src/cli_text.c startup CLI text
|
src/cli_text.c startup CLI text
|
||||||
|
src/tntctl_text.c tntctl local help and diagnostics
|
||||||
src/command_catalog.c command metadata, usage, argument shape
|
src/command_catalog.c command metadata, usage, argument shape
|
||||||
src/ssh_server.c SSH listener and server setup
|
src/ssh_server.c SSH listener and server setup
|
||||||
src/bootstrap.c SSH auth/session bootstrap
|
src/bootstrap.c SSH auth/session bootstrap
|
||||||
|
|
|
||||||
28
include/tntctl_text.h
Normal file
28
include/tntctl_text.h
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef TNTCTL_TEXT_H
|
||||||
|
#define TNTCTL_TEXT_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TNTCTL_TEXT_USAGE,
|
||||||
|
TNTCTL_TEXT_INVALID_PORT,
|
||||||
|
TNTCTL_TEXT_INVALID_LOGIN,
|
||||||
|
TNTCTL_TEXT_INVALID_HOST_KEY_MODE,
|
||||||
|
TNTCTL_TEXT_INVALID_KNOWN_HOSTS,
|
||||||
|
TNTCTL_TEXT_UNKNOWN_OPTION_FORMAT,
|
||||||
|
TNTCTL_TEXT_MISSING_HOST,
|
||||||
|
TNTCTL_TEXT_INVALID_HOST,
|
||||||
|
TNTCTL_TEXT_LOGIN_HOST_CONFLICT,
|
||||||
|
TNTCTL_TEXT_UNKNOWN_COMMAND,
|
||||||
|
TNTCTL_TEXT_INVALID_REMOTE_COMMAND,
|
||||||
|
TNTCTL_TEXT_DESTINATION_TOO_LONG,
|
||||||
|
TNTCTL_TEXT_INVALID_DESTINATION,
|
||||||
|
TNTCTL_TEXT_OUT_OF_MEMORY,
|
||||||
|
TNTCTL_TEXT_HOST_KEY_OPTION_TOO_LONG,
|
||||||
|
TNTCTL_TEXT_KNOWN_HOSTS_OPTION_TOO_LONG,
|
||||||
|
TNTCTL_TEXT_COUNT
|
||||||
|
} tntctl_text_id_t;
|
||||||
|
|
||||||
|
const char *tntctl_text(ui_lang_t lang, tntctl_text_id_t id);
|
||||||
|
|
||||||
|
#endif /* TNTCTL_TEXT_H */
|
||||||
108
src/tntctl.c
108
src/tntctl.c
|
|
@ -1,6 +1,7 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "exec_catalog.h"
|
#include "exec_catalog.h"
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
#include "tntctl_text.h"
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
@ -8,113 +9,6 @@
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
TNTCTL_TEXT_USAGE,
|
|
||||||
TNTCTL_TEXT_INVALID_PORT,
|
|
||||||
TNTCTL_TEXT_INVALID_LOGIN,
|
|
||||||
TNTCTL_TEXT_INVALID_HOST_KEY_MODE,
|
|
||||||
TNTCTL_TEXT_INVALID_KNOWN_HOSTS,
|
|
||||||
TNTCTL_TEXT_UNKNOWN_OPTION_FORMAT,
|
|
||||||
TNTCTL_TEXT_MISSING_HOST,
|
|
||||||
TNTCTL_TEXT_INVALID_HOST,
|
|
||||||
TNTCTL_TEXT_LOGIN_HOST_CONFLICT,
|
|
||||||
TNTCTL_TEXT_UNKNOWN_COMMAND,
|
|
||||||
TNTCTL_TEXT_INVALID_REMOTE_COMMAND,
|
|
||||||
TNTCTL_TEXT_DESTINATION_TOO_LONG,
|
|
||||||
TNTCTL_TEXT_INVALID_DESTINATION,
|
|
||||||
TNTCTL_TEXT_OUT_OF_MEMORY,
|
|
||||||
TNTCTL_TEXT_HOST_KEY_OPTION_TOO_LONG,
|
|
||||||
TNTCTL_TEXT_KNOWN_HOSTS_OPTION_TOO_LONG,
|
|
||||||
TNTCTL_TEXT_COUNT
|
|
||||||
} tntctl_text_id_t;
|
|
||||||
|
|
||||||
static const i18n_string_t tntctl_text_catalog[TNTCTL_TEXT_COUNT] = {
|
|
||||||
[TNTCTL_TEXT_USAGE] = I18N_STRING(
|
|
||||||
"Usage: tntctl [options] host command [args...]\n"
|
|
||||||
"\n"
|
|
||||||
"Options:\n"
|
|
||||||
" -p, --port PORT SSH port (default: 2222)\n"
|
|
||||||
" -l, --login USER SSH login name for exec identity\n"
|
|
||||||
" --host-key-checking MODE\n"
|
|
||||||
" OpenSSH host-key mode: yes, accept-new, no\n"
|
|
||||||
" --known-hosts FILE OpenSSH known_hosts file\n"
|
|
||||||
" -V, --version Print version and exit\n"
|
|
||||||
" -h, --help Print this help and exit\n"
|
|
||||||
"\n"
|
|
||||||
"Commands mirror the TNT SSH exec interface: health, stats, users,\n"
|
|
||||||
"tail, dump, post, help, and exit.\n",
|
|
||||||
"用法: tntctl [options] host command [args...]\n"
|
|
||||||
"\n"
|
|
||||||
"选项:\n"
|
|
||||||
" -p, --port PORT SSH 端口 (默认: 2222)\n"
|
|
||||||
" -l, --login USER SSH 登录名,用作 exec 身份\n"
|
|
||||||
" --host-key-checking MODE\n"
|
|
||||||
" OpenSSH 主机密钥模式: yes, accept-new, no\n"
|
|
||||||
" --known-hosts FILE OpenSSH known_hosts 文件\n"
|
|
||||||
" -V, --version 输出版本并退出\n"
|
|
||||||
" -h, --help 输出此帮助并退出\n"
|
|
||||||
"\n"
|
|
||||||
"命令对应 TNT SSH exec 接口: health, stats, users,\n"
|
|
||||||
"tail, dump, post, help 和 exit.\n"
|
|
||||||
),
|
|
||||||
[TNTCTL_TEXT_INVALID_PORT] = I18N_STRING(
|
|
||||||
"invalid port", "端口无效"
|
|
||||||
),
|
|
||||||
[TNTCTL_TEXT_INVALID_LOGIN] = I18N_STRING(
|
|
||||||
"invalid login", "登录名无效"
|
|
||||||
),
|
|
||||||
[TNTCTL_TEXT_INVALID_HOST_KEY_MODE] = I18N_STRING(
|
|
||||||
"invalid host-key checking mode", "主机密钥检查模式无效"
|
|
||||||
),
|
|
||||||
[TNTCTL_TEXT_INVALID_KNOWN_HOSTS] = I18N_STRING(
|
|
||||||
"invalid known_hosts path", "known_hosts 路径无效"
|
|
||||||
),
|
|
||||||
[TNTCTL_TEXT_UNKNOWN_OPTION_FORMAT] = I18N_STRING(
|
|
||||||
"unknown option: %s", "未知选项: %s"
|
|
||||||
),
|
|
||||||
[TNTCTL_TEXT_MISSING_HOST] = I18N_STRING(
|
|
||||||
"missing host", "缺少 host"
|
|
||||||
),
|
|
||||||
[TNTCTL_TEXT_INVALID_HOST] = I18N_STRING(
|
|
||||||
"invalid host", "host 无效"
|
|
||||||
),
|
|
||||||
[TNTCTL_TEXT_LOGIN_HOST_CONFLICT] = I18N_STRING(
|
|
||||||
"use either --login or user@host, not both",
|
|
||||||
"只能使用 --login 或 user@host 之一"
|
|
||||||
),
|
|
||||||
[TNTCTL_TEXT_UNKNOWN_COMMAND] = I18N_STRING(
|
|
||||||
"unknown or missing command", "未知命令或缺少命令"
|
|
||||||
),
|
|
||||||
[TNTCTL_TEXT_INVALID_REMOTE_COMMAND] = I18N_STRING(
|
|
||||||
"invalid or too-long command", "命令无效或过长"
|
|
||||||
),
|
|
||||||
[TNTCTL_TEXT_DESTINATION_TOO_LONG] = I18N_STRING(
|
|
||||||
"destination too long", "目标地址过长"
|
|
||||||
),
|
|
||||||
[TNTCTL_TEXT_INVALID_DESTINATION] = I18N_STRING(
|
|
||||||
"invalid destination", "目标地址无效"
|
|
||||||
),
|
|
||||||
[TNTCTL_TEXT_OUT_OF_MEMORY] = I18N_STRING(
|
|
||||||
"out of memory", "内存不足"
|
|
||||||
),
|
|
||||||
[TNTCTL_TEXT_HOST_KEY_OPTION_TOO_LONG] = I18N_STRING(
|
|
||||||
"host-key option too long", "主机密钥选项过长"
|
|
||||||
),
|
|
||||||
[TNTCTL_TEXT_KNOWN_HOSTS_OPTION_TOO_LONG] = I18N_STRING(
|
|
||||||
"known_hosts option too long", "known_hosts 选项过长"
|
|
||||||
)
|
|
||||||
};
|
|
||||||
typedef char tntctl_text_catalog_must_cover_enum[
|
|
||||||
sizeof(tntctl_text_catalog) / sizeof(tntctl_text_catalog[0]) ==
|
|
||||||
TNTCTL_TEXT_COUNT ? 1 : -1];
|
|
||||||
|
|
||||||
static const char *tntctl_text(ui_lang_t lang, tntctl_text_id_t id) {
|
|
||||||
if (id < 0 || id >= TNTCTL_TEXT_COUNT) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return i18n_string(tntctl_text_catalog[id], lang);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_usage(FILE *stream, ui_lang_t lang) {
|
static void print_usage(FILE *stream, ui_lang_t lang) {
|
||||||
fputs(tntctl_text(lang, TNTCTL_TEXT_USAGE), stream);
|
fputs(tntctl_text(lang, TNTCTL_TEXT_USAGE), stream);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
89
src/tntctl_text.c
Normal file
89
src/tntctl_text.c
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
#include "tntctl_text.h"
|
||||||
|
|
||||||
|
#include "i18n.h"
|
||||||
|
|
||||||
|
static const i18n_string_t text_catalog[TNTCTL_TEXT_COUNT] = {
|
||||||
|
[TNTCTL_TEXT_USAGE] = I18N_STRING(
|
||||||
|
"Usage: tntctl [options] host command [args...]\n"
|
||||||
|
"\n"
|
||||||
|
"Options:\n"
|
||||||
|
" -p, --port PORT SSH port (default: 2222)\n"
|
||||||
|
" -l, --login USER SSH login name for exec identity\n"
|
||||||
|
" --host-key-checking MODE\n"
|
||||||
|
" OpenSSH host-key mode: yes, accept-new, no\n"
|
||||||
|
" --known-hosts FILE OpenSSH known_hosts file\n"
|
||||||
|
" -V, --version Print version and exit\n"
|
||||||
|
" -h, --help Print this help and exit\n"
|
||||||
|
"\n"
|
||||||
|
"Commands mirror the TNT SSH exec interface: health, stats, users,\n"
|
||||||
|
"tail, dump, post, help, and exit.\n",
|
||||||
|
"用法: tntctl [options] host command [args...]\n"
|
||||||
|
"\n"
|
||||||
|
"选项:\n"
|
||||||
|
" -p, --port PORT SSH 端口 (默认: 2222)\n"
|
||||||
|
" -l, --login USER SSH 登录名,用作 exec 身份\n"
|
||||||
|
" --host-key-checking MODE\n"
|
||||||
|
" OpenSSH 主机密钥模式: yes, accept-new, no\n"
|
||||||
|
" --known-hosts FILE OpenSSH known_hosts 文件\n"
|
||||||
|
" -V, --version 输出版本并退出\n"
|
||||||
|
" -h, --help 输出此帮助并退出\n"
|
||||||
|
"\n"
|
||||||
|
"命令对应 TNT SSH exec 接口: health, stats, users,\n"
|
||||||
|
"tail, dump, post, help 和 exit.\n"
|
||||||
|
),
|
||||||
|
[TNTCTL_TEXT_INVALID_PORT] = I18N_STRING(
|
||||||
|
"invalid port", "端口无效"
|
||||||
|
),
|
||||||
|
[TNTCTL_TEXT_INVALID_LOGIN] = I18N_STRING(
|
||||||
|
"invalid login", "登录名无效"
|
||||||
|
),
|
||||||
|
[TNTCTL_TEXT_INVALID_HOST_KEY_MODE] = I18N_STRING(
|
||||||
|
"invalid host-key checking mode", "主机密钥检查模式无效"
|
||||||
|
),
|
||||||
|
[TNTCTL_TEXT_INVALID_KNOWN_HOSTS] = I18N_STRING(
|
||||||
|
"invalid known_hosts path", "known_hosts 路径无效"
|
||||||
|
),
|
||||||
|
[TNTCTL_TEXT_UNKNOWN_OPTION_FORMAT] = I18N_STRING(
|
||||||
|
"unknown option: %s", "未知选项: %s"
|
||||||
|
),
|
||||||
|
[TNTCTL_TEXT_MISSING_HOST] = I18N_STRING(
|
||||||
|
"missing host", "缺少 host"
|
||||||
|
),
|
||||||
|
[TNTCTL_TEXT_INVALID_HOST] = I18N_STRING(
|
||||||
|
"invalid host", "host 无效"
|
||||||
|
),
|
||||||
|
[TNTCTL_TEXT_LOGIN_HOST_CONFLICT] = I18N_STRING(
|
||||||
|
"use either --login or user@host, not both",
|
||||||
|
"只能使用 --login 或 user@host 之一"
|
||||||
|
),
|
||||||
|
[TNTCTL_TEXT_UNKNOWN_COMMAND] = I18N_STRING(
|
||||||
|
"unknown or missing command", "未知命令或缺少命令"
|
||||||
|
),
|
||||||
|
[TNTCTL_TEXT_INVALID_REMOTE_COMMAND] = I18N_STRING(
|
||||||
|
"invalid or too-long command", "命令无效或过长"
|
||||||
|
),
|
||||||
|
[TNTCTL_TEXT_DESTINATION_TOO_LONG] = I18N_STRING(
|
||||||
|
"destination too long", "目标地址过长"
|
||||||
|
),
|
||||||
|
[TNTCTL_TEXT_INVALID_DESTINATION] = I18N_STRING(
|
||||||
|
"invalid destination", "目标地址无效"
|
||||||
|
),
|
||||||
|
[TNTCTL_TEXT_OUT_OF_MEMORY] = I18N_STRING(
|
||||||
|
"out of memory", "内存不足"
|
||||||
|
),
|
||||||
|
[TNTCTL_TEXT_HOST_KEY_OPTION_TOO_LONG] = I18N_STRING(
|
||||||
|
"host-key option too long", "主机密钥选项过长"
|
||||||
|
),
|
||||||
|
[TNTCTL_TEXT_KNOWN_HOSTS_OPTION_TOO_LONG] = I18N_STRING(
|
||||||
|
"known_hosts option too long", "known_hosts 选项过长"
|
||||||
|
)
|
||||||
|
};
|
||||||
|
typedef char text_catalog_must_cover_enum[
|
||||||
|
sizeof(text_catalog) / sizeof(text_catalog[0]) == TNTCTL_TEXT_COUNT ? 1 : -1];
|
||||||
|
|
||||||
|
const char *tntctl_text(ui_lang_t lang, tntctl_text_id_t id) {
|
||||||
|
if (id < 0 || id >= TNTCTL_TEXT_COUNT) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return i18n_string(text_catalog[id], lang);
|
||||||
|
}
|
||||||
|
|
@ -16,6 +16,7 @@ MESSAGE_LOG_SRC = ../../src/message_log.c
|
||||||
COMMON_SRC = ../../src/common.c
|
COMMON_SRC = ../../src/common.c
|
||||||
COMMAND_CATALOG_SRC = ../../src/command_catalog.c
|
COMMAND_CATALOG_SRC = ../../src/command_catalog.c
|
||||||
CLI_TEXT_SRC = ../../src/cli_text.c
|
CLI_TEXT_SRC = ../../src/cli_text.c
|
||||||
|
TNTCTL_TEXT_SRC = ../../src/tntctl_text.c
|
||||||
CHAT_ROOM_SRC = ../../src/chat_room.c
|
CHAT_ROOM_SRC = ../../src/chat_room.c
|
||||||
HISTORY_VIEW_SRC = ../../src/history_view.c
|
HISTORY_VIEW_SRC = ../../src/history_view.c
|
||||||
I18N_SRC = ../../src/i18n.c
|
I18N_SRC = ../../src/i18n.c
|
||||||
|
|
@ -26,7 +27,7 @@ HELP_TEXT_SRC = ../../src/help_text.c
|
||||||
MANUAL_TEXT_SRC = ../../src/manual_text.c
|
MANUAL_TEXT_SRC = ../../src/manual_text.c
|
||||||
RATELIMIT_SRC = ../../src/ratelimit.c
|
RATELIMIT_SRC = ../../src/ratelimit.c
|
||||||
|
|
||||||
TESTS = test_utf8 test_message test_chat_room test_history_view test_i18n test_system_message test_command_catalog test_exec_catalog test_help_text test_manual_text test_cli_text test_ratelimit
|
TESTS = test_utf8 test_message test_chat_room test_history_view test_i18n test_system_message test_command_catalog test_exec_catalog test_help_text test_manual_text test_cli_text test_tntctl_text test_ratelimit
|
||||||
|
|
||||||
.PHONY: all clean run
|
.PHONY: all clean run
|
||||||
|
|
||||||
|
|
@ -65,6 +66,9 @@ test_manual_text: test_manual_text.c $(MANUAL_TEXT_SRC) $(COMMAND_CATALOG_SRC) $
|
||||||
test_cli_text: test_cli_text.c $(CLI_TEXT_SRC) $(COMMON_SRC)
|
test_cli_text: test_cli_text.c $(CLI_TEXT_SRC) $(COMMON_SRC)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
test_tntctl_text: test_tntctl_text.c $(TNTCTL_TEXT_SRC)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
test_ratelimit: test_ratelimit.c $(RATELIMIT_SRC) $(COMMON_SRC)
|
test_ratelimit: test_ratelimit.c $(RATELIMIT_SRC) $(COMMON_SRC)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
|
@ -102,6 +106,9 @@ run: all
|
||||||
@echo "=== Running CLI Text Tests ==="
|
@echo "=== Running CLI Text Tests ==="
|
||||||
./test_cli_text
|
./test_cli_text
|
||||||
@echo ""
|
@echo ""
|
||||||
|
@echo "=== Running tntctl Text Tests ==="
|
||||||
|
./test_tntctl_text
|
||||||
|
@echo ""
|
||||||
@echo "=== Running Rate Limit Tests ==="
|
@echo "=== Running Rate Limit Tests ==="
|
||||||
./test_ratelimit
|
./test_ratelimit
|
||||||
|
|
||||||
|
|
|
||||||
53
tests/unit/test_tntctl_text.c
Normal file
53
tests/unit/test_tntctl_text.c
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
/* Unit tests for tntctl local help and diagnostic text */
|
||||||
|
|
||||||
|
#include "../../include/tntctl_text.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define TEST(name) static void test_##name()
|
||||||
|
#define RUN_TEST(name) do { \
|
||||||
|
printf("Running %s... ", #name); \
|
||||||
|
test_##name(); \
|
||||||
|
printf("✓\n"); \
|
||||||
|
tests_passed++; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
static int tests_passed = 0;
|
||||||
|
|
||||||
|
TEST(usage_matches_language) {
|
||||||
|
const char *en = tntctl_text(UI_LANG_EN, TNTCTL_TEXT_USAGE);
|
||||||
|
const char *zh = tntctl_text(UI_LANG_ZH, TNTCTL_TEXT_USAGE);
|
||||||
|
|
||||||
|
assert(strstr(en, "Usage: tntctl [options] host command [args...]") != NULL);
|
||||||
|
assert(strstr(en, "--host-key-checking MODE") != NULL);
|
||||||
|
assert(strstr(en, "health, stats, users") != NULL);
|
||||||
|
assert(strstr(zh, "用法: tntctl [options] host command [args...]") != NULL);
|
||||||
|
assert(strstr(zh, "OpenSSH 主机密钥模式") != NULL);
|
||||||
|
assert(strstr(zh, "health, stats, users") != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(errors_match_language) {
|
||||||
|
assert(strcmp(tntctl_text(UI_LANG_EN, TNTCTL_TEXT_INVALID_PORT),
|
||||||
|
"invalid port") == 0);
|
||||||
|
assert(strcmp(tntctl_text(UI_LANG_ZH, TNTCTL_TEXT_INVALID_PORT),
|
||||||
|
"端口无效") == 0);
|
||||||
|
assert(strcmp(tntctl_text(UI_LANG_EN, TNTCTL_TEXT_UNKNOWN_OPTION_FORMAT),
|
||||||
|
"unknown option: %s") == 0);
|
||||||
|
assert(strcmp(tntctl_text(UI_LANG_ZH, TNTCTL_TEXT_UNKNOWN_OPTION_FORMAT),
|
||||||
|
"未知选项: %s") == 0);
|
||||||
|
assert(strcmp(tntctl_text((ui_lang_t)99, TNTCTL_TEXT_INVALID_PORT),
|
||||||
|
"invalid port") == 0);
|
||||||
|
assert(strcmp(tntctl_text(UI_LANG_EN,
|
||||||
|
(tntctl_text_id_t)TNTCTL_TEXT_COUNT), "") == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
printf("Running tntctl text unit tests...\n\n");
|
||||||
|
|
||||||
|
RUN_TEST(usage_matches_language);
|
||||||
|
RUN_TEST(errors_match_language);
|
||||||
|
|
||||||
|
printf("\n✓ All %d tests passed!\n", tests_passed);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue