first commit
Some checks failed
CI/CD Pipeline / Test (push) Failing after 22m19s
CI/CD Pipeline / Security Scan (push) Failing after 5m57s
CI/CD Pipeline / Build (amd64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (amd64, linux) (push) Has been skipped
CI/CD Pipeline / Build (amd64, windows) (push) Has been skipped
CI/CD Pipeline / Build (arm64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (arm64, linux) (push) Has been skipped
CI/CD Pipeline / Build Docker Image (push) Has been skipped
CI/CD Pipeline / Create Release (push) Has been skipped
Some checks failed
CI/CD Pipeline / Test (push) Failing after 22m19s
CI/CD Pipeline / Security Scan (push) Failing after 5m57s
CI/CD Pipeline / Build (amd64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (amd64, linux) (push) Has been skipped
CI/CD Pipeline / Build (amd64, windows) (push) Has been skipped
CI/CD Pipeline / Build (arm64, darwin) (push) Has been skipped
CI/CD Pipeline / Build (arm64, linux) (push) Has been skipped
CI/CD Pipeline / Build Docker Image (push) Has been skipped
CI/CD Pipeline / Create Release (push) Has been skipped
This commit is contained in:
169
internal/conversion/engine_internal_test.go
Normal file
169
internal/conversion/engine_internal_test.go
Normal file
@@ -0,0 +1,169 @@
|
||||
package conversion
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/subconverter-go/internal/config"
|
||||
"github.com/subconverter-go/internal/generator"
|
||||
"github.com/subconverter-go/internal/logging"
|
||||
"github.com/subconverter-go/internal/parser"
|
||||
)
|
||||
|
||||
func newTestConversionEngine(t *testing.T) *ConversionEngine {
|
||||
t.Helper()
|
||||
|
||||
logger, err := logging.NewLogger(&logging.LoggingConfig{
|
||||
Level: "error",
|
||||
Format: "text",
|
||||
Output: "stdout",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create logger: %v", err)
|
||||
}
|
||||
|
||||
configMgr, err := config.NewConfigManager("")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create config manager: %v", err)
|
||||
}
|
||||
|
||||
parserMgr := parser.NewParserManager(logger, configMgr)
|
||||
generatorMgr := generator.NewGeneratorManager(logger)
|
||||
|
||||
return NewConversionEngine(logger, parserMgr, generatorMgr)
|
||||
}
|
||||
|
||||
func TestTrimLineCleansCommentsAndBom(t *testing.T) {
|
||||
engine := newTestConversionEngine(t)
|
||||
|
||||
cases := map[string]string{
|
||||
"\ufeff ss://example": "ss://example",
|
||||
"# leading comment": "",
|
||||
" // spaced comment": "",
|
||||
"\t;remark": "",
|
||||
"ss://example": "ss://example",
|
||||
}
|
||||
|
||||
for input, expected := range cases {
|
||||
if got := engine.trimLine(input); got != expected {
|
||||
t.Fatalf("trimLine(%q) = %q, expected %q", input, got, expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseConfigurationsHandlesLegacyProtocols(t *testing.T) {
|
||||
engine := newTestConversionEngine(t)
|
||||
|
||||
vmessPayload := "eyJ2IjoiMiIsInBzIjoidGVzdCIsImFkZCI6IjE5Mi4xNjguMS4xIiwicG9ydCI6IjQ0MyIsImlkIjoiMTIzNDU2NzgtMTIzNC0xMjM0LTEyMzQtMTIzNDU2Nzg5MDEyIiwiYWlkIjoiMCIsIm5ldCI6IndzIiwidHlwZSI6Im5vbmUiLCJob3N0IjoidGVzdC5jb20iLCJwYXRoIjoiL3Rlc3QiLCJ0bHMiOiJ0bHMifQ=="
|
||||
|
||||
input := "\ufeff# first line is a comment\n" +
|
||||
"socks://user:pass@example.com:1080#socks-proxy\n" +
|
||||
"vmess1://" + vmessPayload + "\n"
|
||||
|
||||
configs, result, err := engine.parseConfigurations(input, true)
|
||||
if err != nil {
|
||||
t.Fatalf("parseConfigurations returned error: %v", err)
|
||||
}
|
||||
|
||||
if len(result.InvalidInputs) != 0 {
|
||||
t.Fatalf("expected no invalid inputs, got %v", result.InvalidInputs)
|
||||
}
|
||||
|
||||
if len(configs) != 2 {
|
||||
t.Fatalf("expected 2 valid configs, got %d", len(configs))
|
||||
}
|
||||
|
||||
protocols := []string{configs[0].Protocol, configs[1].Protocol}
|
||||
expected := map[string]bool{"socks5": false, "vmess": false}
|
||||
for _, protocol := range protocols {
|
||||
if _, ok := expected[protocol]; !ok {
|
||||
t.Fatalf("unexpected protocol parsed: %s", protocol)
|
||||
}
|
||||
expected[protocol] = true
|
||||
}
|
||||
|
||||
for proto, seen := range expected {
|
||||
if !seen {
|
||||
t.Fatalf("protocol %s not detected in parsed configs", proto)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateStatsIncludedInDebugInfo(t *testing.T) {
|
||||
engine := newTestConversionEngine(t)
|
||||
|
||||
req := &ConversionRequest{Target: "clash", URL: "https://example.com"}
|
||||
configs := []*parser.ProxyConfig{{Protocol: "socks5"}}
|
||||
parseResult := &ParseResult{
|
||||
ValidConfigs: configs,
|
||||
ProtocolStats: map[string]int{"socks5": 1},
|
||||
}
|
||||
generation := &GenerateResult{
|
||||
GeneratedOutput: "payload",
|
||||
FormatFeatures: map[string]bool{"success": true},
|
||||
GenerateStats: &GenerateStats{
|
||||
GeneratedProxies: 1,
|
||||
GeneratedGroups: 2,
|
||||
GeneratedRules: 3,
|
||||
FormatFeatures: map[string]bool{"success": true},
|
||||
},
|
||||
}
|
||||
|
||||
resp := engine.createSuccessResponse(req, "payload", configs, parseResult, generation)
|
||||
statsVal, ok := resp.DebugInfo["generate_stats"].(map[string]interface{})
|
||||
if !ok {
|
||||
t.Fatalf("expected generate_stats in debug info, got %v", resp.DebugInfo)
|
||||
}
|
||||
|
||||
if statsVal["generated_proxies"].(int) != 1 {
|
||||
t.Fatalf("expected generated_proxies=1, got %v", statsVal["generated_proxies"])
|
||||
}
|
||||
if statsVal["generated_groups"].(int) != 2 {
|
||||
t.Fatalf("expected generated_groups=2, got %v", statsVal["generated_groups"])
|
||||
}
|
||||
if statsVal["generated_rules"].(int) != 3 {
|
||||
t.Fatalf("expected generated_rules=3, got %v", statsVal["generated_rules"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveLeadingEmojiHandlesVariants(t *testing.T) {
|
||||
cases := map[string]string{
|
||||
"🛰️ ss-192.168.1.1:8388": "ss-192.168.1.1:8388",
|
||||
"🇭🇰 ss-node": "ss-node",
|
||||
"🇭🇰ss-node": "ss-node",
|
||||
" ss-node": "ss-node",
|
||||
"": "",
|
||||
}
|
||||
|
||||
for input, expected := range cases {
|
||||
if got := removeLeadingEmoji(input); got != expected {
|
||||
t.Fatalf("removeLeadingEmoji(%q) = %q, want %q", input, got, expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyTransformationsRemoveEmojiAfterRename(t *testing.T) {
|
||||
engine := newTestConversionEngine(t)
|
||||
req := NewConversionRequest()
|
||||
req.RenameRules = []string{".*@🇭🇰 $0"}
|
||||
req.RemoveEmoji = true
|
||||
|
||||
config := &parser.ProxyConfig{
|
||||
Name: "ss-192.168.1.1:8388",
|
||||
Remarks: "",
|
||||
Protocol: "ss",
|
||||
Type: "ss",
|
||||
Settings: map[string]interface{}{"method": "aes-256-cfb"},
|
||||
}
|
||||
|
||||
updated, err := engine.applyTransformations([]*parser.ProxyConfig{config}, req)
|
||||
if err != nil {
|
||||
t.Fatalf("applyTransformations returned error: %v", err)
|
||||
}
|
||||
if len(updated) != 1 {
|
||||
t.Fatalf("expected one config, got %d", len(updated))
|
||||
}
|
||||
|
||||
if updated[0].Name != "ss-192.168.1.1:8388" {
|
||||
t.Fatalf("expected name without emoji, got %q", updated[0].Name)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user