package routers import ( "os" "path/filepath" "testing" ) func setupTestRoutes(t *testing.T) (string, func()) { // Create a temporary directory for test routes tempDir, err := os.MkdirTemp("", "fsrouter-test") if err != nil { t.Fatalf("Failed to create temp directory: %v", err) } // Create route structure with valid Lua code routes := map[string]string{ "get.lua": "return { path = '/' }", "post.lua": "return { path = '/' }", "api/get.lua": "return { path = '/api' }", "api/users/get.lua": "return { path = '/api/users' }", "api/users/[id]/get.lua": "return { path = '/api/users/[id]' }", "api/users/[id]/posts/get.lua": "return { path = '/api/users/[id]/posts' }", "api/[version]/docs/get.lua": "return { path = '/api/[version]/docs' }", } for path, content := range routes { routePath := filepath.Join(tempDir, path) // Create directories err := os.MkdirAll(filepath.Dir(routePath), 0755) if err != nil { t.Fatalf("Failed to create directory %s: %v", filepath.Dir(routePath), err) } // Create file err = os.WriteFile(routePath, []byte(content), 0644) if err != nil { t.Fatalf("Failed to create file %s: %v", routePath, err) } } // Return cleanup function cleanup := func() { os.RemoveAll(tempDir) } return tempDir, cleanup } func TestRouterInitialization(t *testing.T) { routesDir, cleanup := setupTestRoutes(t) defer cleanup() router, err := NewLuaRouter(routesDir) if err != nil { t.Fatalf("Failed to create router: %v", err) } if router == nil { t.Fatal("Router is nil") } } func TestRouteMatching(t *testing.T) { routesDir, cleanup := setupTestRoutes(t) defer cleanup() router, err := NewLuaRouter(routesDir) if err != nil { t.Fatalf("Failed to create router: %v", err) } tests := []struct { method string path string wantFound bool wantParams map[string]string wantHandler string }{ // Static routes {"GET", "/", true, nil, filepath.Join(routesDir, "get.lua")}, {"POST", "/", true, nil, filepath.Join(routesDir, "post.lua")}, {"GET", "/api", true, nil, filepath.Join(routesDir, "api/get.lua")}, {"GET", "/api/users", true, nil, filepath.Join(routesDir, "api/users/get.lua")}, // Parameterized routes {"GET", "/api/users/123", true, map[string]string{"id": "123"}, filepath.Join(routesDir, "api/users/[id]/get.lua")}, {"GET", "/api/users/456/posts", true, map[string]string{"id": "456"}, filepath.Join(routesDir, "api/users/[id]/posts/get.lua")}, {"GET", "/api/v1/docs", true, map[string]string{"version": "v1"}, filepath.Join(routesDir, "api/[version]/docs/get.lua")}, // Non-existent routes {"PUT", "/", false, nil, ""}, {"GET", "/nonexistent", false, nil, ""}, {"GET", "/api/nonexistent", false, nil, ""}, } for _, tt := range tests { t.Run(tt.method+" "+tt.path, func(t *testing.T) { var params Params node, found := router.Match(tt.method, tt.path, ¶ms) if found != tt.wantFound { t.Errorf("Match() found = %v, want %v", found, tt.wantFound) } if !found { return } if node.handler != tt.wantHandler { t.Errorf("Match() handler = %v, want %v", node.handler, tt.wantHandler) } // Verify bytecode was compiled if len(node.bytecode) == 0 { t.Errorf("No bytecode found for handler: %s", node.handler) } // Verify parameters if tt.wantParams != nil { for key, wantValue := range tt.wantParams { gotValue := params.Get(key) if gotValue != wantValue { t.Errorf("Parameter %s = %s, want %s", key, gotValue, wantValue) } } } }) } } func TestParamExtraction(t *testing.T) { routesDir, cleanup := setupTestRoutes(t) defer cleanup() router, err := NewLuaRouter(routesDir) if err != nil { t.Fatalf("Failed to create router: %v", err) } var params Params _, found := router.Match("GET", "/api/v2/docs", ¶ms) if !found { t.Fatalf("Route not found") } if params.Count != 1 { t.Errorf("Expected 1 parameter, got %d", params.Count) } if params.Keys[0] != "version" { t.Errorf("Expected parameter key 'version', got '%s'", params.Keys[0]) } if params.Values[0] != "v2" { t.Errorf("Expected parameter value 'v2', got '%s'", params.Values[0]) } if params.Get("version") != "v2" { t.Errorf("Get(\"version\") returned '%s', expected 'v2'", params.Get("version")) } } func TestGetBytecode(t *testing.T) { routesDir, cleanup := setupTestRoutes(t) defer cleanup() router, err := NewLuaRouter(routesDir) if err != nil { t.Fatalf("Failed to create router: %v", err) } var params Params bytecode, found := router.GetBytecode("GET", "/api/users/123", ¶ms) if !found { t.Fatalf("Route not found") } if len(bytecode) == 0 { t.Errorf("Expected non-empty bytecode") } // Check parameters were extracted if params.Get("id") != "123" { t.Errorf("Expected id parameter '123', got '%s'", params.Get("id")) } } func TestRefresh(t *testing.T) { routesDir, cleanup := setupTestRoutes(t) defer cleanup() router, err := NewLuaRouter(routesDir) if err != nil { t.Fatalf("Failed to create router: %v", err) } // Add a new route file newRoutePath := filepath.Join(routesDir, "new", "get.lua") err = os.MkdirAll(filepath.Dir(newRoutePath), 0755) if err != nil { t.Fatalf("Failed to create directory: %v", err) } err = os.WriteFile(newRoutePath, []byte("return { path = '/new' }"), 0644) if err != nil { t.Fatalf("Failed to create file: %v", err) } // Before refresh, route should not be found var params Params _, found := router.GetBytecode("GET", "/new", ¶ms) if found { t.Errorf("New route should not be found before refresh") } // Refresh router err = router.Refresh() if err != nil { t.Fatalf("Failed to refresh router: %v", err) } // After refresh, route should be found bytecode, found := router.GetBytecode("GET", "/new", ¶ms) if !found { t.Errorf("New route should be found after refresh") } if len(bytecode) == 0 { t.Errorf("Expected non-empty bytecode for new route") } } func TestInvalidRoutesDir(t *testing.T) { // Non-existent directory _, err := NewLuaRouter("/non/existent/directory") if err == nil { t.Error("Expected error for non-existent directory, got nil") } // Create a file instead of a directory tmpFile, err := os.CreateTemp("", "fsrouter-test-file") if err != nil { t.Fatalf("Failed to create temp file: %v", err) } defer os.Remove(tmpFile.Name()) defer tmpFile.Close() _, err = NewLuaRouter(tmpFile.Name()) if err == nil { t.Error("Expected error for file as routes dir, got nil") } }