package destroy import ( "encoding/json" "os" "path/filepath" "testing" ) func TestListResourcesFromState(t *testing.T) { tests := []struct { name string content string want []Resource wantErr bool }{ { name: "empty state", content: `{}`, want: []Resource{}, wantErr: false, }, { name: "state with resources", content: `{"resources":[{"address":"hcloud_server.main","type":"hcloud_server","name":"main"},{"address":"hcloud_volume.data","type":"hcloud_volume","name":"data"}]}`, want: []Resource{ {Address: "hcloud_server.main", Type: "hcloud_server", Name: "main"}, {Address: "hcloud_volume.data", Type: "hcloud_volume", Name: "data"}, }, wantErr: false, }, { name: "state with module resources", content: `{"resources":[{"address":"hcloud_server.main","type":"hcloud_server","name":"main","module":"module.agent"},{"address":"null_resource.provisioner","type":"null_resource","name":"provisioner"}]}`, want: []Resource{ {Address: "module.agent.hcloud_server.main", Type: "hcloud_server", Name: "main"}, {Address: "null_resource.provisioner", Type: "null_resource", Name: "provisioner"}, }, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Create temp file tmpDir := t.TempDir() statePath := filepath.Join(tmpDir, "terraform.tfstate") if err := os.WriteFile(statePath, []byte(tt.content), 0644); err != nil { t.Fatalf("failed to write state file: %v", err) } got, err := listResourcesFromState(statePath) if (err != nil) != tt.wantErr { t.Errorf("listResourcesFromState() error = %v, wantErr %v", err, tt.wantErr) return } if len(got) != len(tt.want) { t.Errorf("listResourcesFromState() got %d resources, want %d", len(got), len(tt.want)) return } for i, r := range got { if r.Address != tt.want[i].Address { t.Errorf("resource[%d].Address = %s, want %s", i, r.Address, tt.want[i].Address) } if r.Type != tt.want[i].Type { t.Errorf("resource[%d].Type = %s, want %s", i, r.Type, tt.want[i].Type) } if r.Name != tt.want[i].Name { t.Errorf("resource[%d].Name = %s, want %s", i, r.Name, tt.want[i].Name) } } }) } } func TestListResourcesFromStateNonExistent(t *testing.T) { _, err := listResourcesFromState("/nonexistent/path/state") if err == nil { t.Error("expected error for non-existent file") } } func TestLoadEnvFile(t *testing.T) { tests := []struct { name string content string want []string wantErr bool }{ { name: "simple key-value", content: "KEY=value\nOTHER=123", want: []string{"KEY=value", "OTHER=123"}, wantErr: false, }, { name: "quoted values", content: `KEY="quoted value"` + "\n" + `OTHER='single quoted'`, want: []string{"KEY=quoted value", "OTHER=single quoted"}, wantErr: false, }, { name: "comments and blank lines", content: "# comment\n\nKEY=value\n# another comment\n", want: []string{"KEY=value"}, wantErr: false, }, { name: "empty file", content: "", want: []string{}, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Create temp file tmpFile := filepath.Join(t.TempDir(), ".env") if err := os.WriteFile(tmpFile, []byte(tt.content), 0644); err != nil { t.Fatalf("failed to write env file: %v", err) } got, err := loadEnvFile(tmpFile) if (err != nil) != tt.wantErr { t.Errorf("loadEnvFile() error = %v, wantErr %v", err, tt.wantErr) return } if len(got) != len(tt.want) { t.Errorf("loadEnvFile() got %d entries, want %d", len(got), len(tt.want)) return } for i, v := range got { if v != tt.want[i] { t.Errorf("env[%d] = %s, want %s", i, v, tt.want[i]) } } }) } } func TestFileExists(t *testing.T) { tmpDir := t.TempDir() // Test existing file existingFile := filepath.Join(tmpDir, "exists") if err := os.WriteFile(existingFile, []byte("test"), 0644); err != nil { t.Fatal(err) } if !fileExists(existingFile) { t.Error("fileExists() returned false for existing file") } // Test non-existent file if fileExists(filepath.Join(tmpDir, "nonexistent")) { t.Error("fileExists() returned true for non-existent file") } // Test directory (should return false) if fileExists(tmpDir) { t.Error("fileExists() returned true for directory") } } func TestDirExists(t *testing.T) { tmpDir := t.TempDir() // Test existing directory if !dirExists(tmpDir) { t.Error("dirExists() returned false for existing directory") } // Test non-existent directory if dirExists(filepath.Join(tmpDir, "nonexistent")) { t.Error("dirExists() returned true for non-existent directory") } // Test file (should return false) existingFile := filepath.Join(tmpDir, "file") if err := os.WriteFile(existingFile, []byte("test"), 0644); err != nil { t.Fatal(err) } if dirExists(existingFile) { t.Error("dirExists() returned true for file") } } func TestCleanupStateFiles(t *testing.T) { tmpDir := t.TempDir() // Create state files stateFiles := []string{ "terraform.tfstate", "terraform.tfstate.backup", ".terraform.lock.hcl", } for _, f := range stateFiles { if err := os.WriteFile(filepath.Join(tmpDir, f), []byte("{}"), 0644); err != nil { t.Fatal(err) } } // Create .terraform directory tfDir := filepath.Join(tmpDir, ".terraform") if err := os.MkdirAll(tfDir, 0755); err != nil { t.Fatal(err) } // Run cleanup cleanupStateFiles(tmpDir) // Verify files are deleted for _, f := range stateFiles { if fileExists(filepath.Join(tmpDir, f)) { t.Errorf("state file %s was not deleted", f) } } if dirExists(tfDir) { t.Error(".terraform directory was not deleted") } } func TestResourceJSONMarshal(t *testing.T) { // Verify Resource struct can be marshaled/unmarshaled if needed res := Resource{ Address: "hcloud_server.main", Type: "hcloud_server", Name: "main", } data, err := json.Marshal(res) if err != nil { t.Fatalf("failed to marshal Resource: %v", err) } var got Resource if err := json.Unmarshal(data, &got); err != nil { t.Fatalf("failed to unmarshal Resource: %v", err) } if got.Address != res.Address || got.Type != res.Type || got.Name != res.Name { t.Errorf("marshal/unmarshal roundtrip failed: got %+v, want %+v", got, res) } } func TestOptionsDefaults(t *testing.T) { // Test that Options struct can be created with defaults opts := &Options{} if opts.AutoApprove != false { t.Error("default AutoApprove should be false") } if opts.WorkDir != "" { t.Error("default WorkDir should be empty") } if opts.KeepState != false { t.Error("default KeepState should be false") } }