From 7d13c985f881722ee63bff53c42e5171bcde572b Mon Sep 17 00:00:00 2001 From: Matt Trachier Date: Wed, 1 Oct 2025 23:41:08 -0500 Subject: [PATCH] fix: sort directory file info objects (#209) Signed-off-by: matttrach (cherry picked from commit ff5bc8dc7e07b22641feb7f72848bc003f0d678e) --- .../directory_data_source.go | 11 +++- .../directory_data_source_test.go | 60 +++++++++++-------- 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/internal/provider/file_local_directory/directory_data_source.go b/internal/provider/file_local_directory/directory_data_source.go index 2a03e92..dbdd338 100644 --- a/internal/provider/file_local_directory/directory_data_source.go +++ b/internal/provider/file_local_directory/directory_data_source.go @@ -7,6 +7,7 @@ import ( "crypto/sha256" "encoding/hex" "fmt" + "sort" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" @@ -139,7 +140,7 @@ func (r *LocalDirectoryDataSource) Read(ctx context.Context, req datasource.Read } config.Permissions = types.StringValue(perm) - config.Files = []LocalDirectoryFileInfoModel{} + fileList := []LocalDirectoryFileInfoModel{} for fileName, fileData := range files { fileInfo := LocalDirectoryFileInfoModel{ Name: types.StringValue(fileName), @@ -148,8 +149,14 @@ func (r *LocalDirectoryDataSource) Read(ctx context.Context, req datasource.Read LastModified: types.StringValue(fileData["ModTime"]), IsDirectory: types.StringValue(fileData["IsDir"]), } - config.Files = append(config.Files, fileInfo) + fileList = append(fileList, fileInfo) } + // Sort files by name (alphabetically) + sort.Slice(fileList, func(i, j int) bool { + return fileList[i].Name.ValueString() < fileList[j].Name.ValueString() + }) + + config.Files = fileList resp.Diagnostics.Append(resp.State.Set(ctx, &config)...) tflog.Debug(ctx, fmt.Sprintf("Response Object: %#v", *resp)) diff --git a/internal/provider/file_local_directory/directory_data_source_test.go b/internal/provider/file_local_directory/directory_data_source_test.go index 5911457..06801bb 100644 --- a/internal/provider/file_local_directory/directory_data_source_test.go +++ b/internal/provider/file_local_directory/directory_data_source_test.go @@ -6,6 +6,7 @@ import ( "context" "math/rand" "path/filepath" + "sort" "strconv" "testing" "time" @@ -119,24 +120,18 @@ func TestLocalDirectoryDataSourceRead(t *testing.T) { if !ok { t.Fatalf("files is not a []map[string]string") } + created, err := tc.fit.client.Create(path, permissions) if err != nil { t.Errorf("Error setting up: %v", err) return } - characterSet := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - rand := rand.New(rand.NewSource(time.Now().UnixNano())) for _, file := range files { - size, err := strconv.Atoi(file["size"]) + contents, err := getRandomString(file["size"]) if err != nil { - t.Errorf("could not convert size '%s' to an integer: %v", file["size"], err) + t.Errorf("Error generating random string: %v", err) return } - b := make([]byte, size) - for i := range b { - b[i] = characterSet[rand.Intn(len(characterSet))] - } - contents := string(b) err = tc.fit.client.CreateFile(filepath.Join(path, file["name"]), contents, file["permissions"], file["lastModified"]) if err != nil { t.Errorf("Error setting up: %v", err) @@ -152,26 +147,27 @@ func TestLocalDirectoryDataSourceRead(t *testing.T) { r := getReadDataSourceResponseContainer() tc.fit.Read(context.Background(), tc.have, &r) got := r - val := map[string]tftypes.Value{} - err = tc.want.State.Raw.As(&val) - if err != nil { - t.Errorf("Error converting tc.want.State.Raw to map: %v", err) - return - } - rawWantFiles := val["files"] - err = got.State.Raw.As(&val) - if err != nil { - t.Errorf("Error converting got.State.Raw to map: %v", err) - return + var wantState LocalDirectoryDataSourceModel + diags := tc.want.State.Get(context.Background(), &wantState) + if diags.HasError() { + t.Fatalf("error getting want state: %v", diags) } - rawGotFiles := val["files"] - if diff := cmp.Diff(rawWantFiles, rawGotFiles); diff != "" { - t.Errorf("Read() mismatch (-want +got):\n%s", diff) - return + var gotState LocalDirectoryDataSourceModel + diags = got.State.Get(context.Background(), &gotState) + if diags.HasError() { + t.Fatalf("error getting got state: %v", diags) } - if diff := cmp.Diff(tc.want, got); diff != "" { + + sort.Slice(wantState.Files, func(i, j int) bool { + return wantState.Files[i].Name.ValueString() < wantState.Files[j].Name.ValueString() + }) + sort.Slice(gotState.Files, func(i, j int) bool { + return gotState.Files[i].Name.ValueString() < gotState.Files[j].Name.ValueString() + }) + + if diff := cmp.Diff(wantState, gotState); diff != "" { t.Errorf("Read() mismatch (-want +got):\n%s", diff) return } @@ -303,3 +299,17 @@ func getLocalDirectoryDataSourceSchema() *datasource.SchemaResponse { testResource.Schema(context.Background(), datasource.SchemaRequest{}, r) return r } + +func getRandomString(n string) (string, error) { + size, err := strconv.Atoi(n) + if err != nil { + return "", err + } + const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + r := rand.New(rand.NewSource(time.Now().UnixNano())) + b := make([]byte, size) + for i := 0; i < size; i++ { + b[i] = letterBytes[r.Intn(len(letterBytes))] + } + return string(b), nil +}