diff --git a/globals.go b/globals.go index 97436d3..f734cfb 100644 --- a/globals.go +++ b/globals.go @@ -1,6 +1,7 @@ package sdk import ( + "bytes" "encoding/json" "reflect" "strings" @@ -63,43 +64,82 @@ type Cacher interface { } func convertObjectToArray(field, strIn string) string { - convertToArray := func(field, str string) (string, bool) { - find := "\"" + field + "\": {" - start := strings.Index(str, find) - if start == -1 { - return str, false + // We’ll look for this pattern: `"field":` + pattern := []byte("\"" + field + "\":") + in := []byte(strIn) + + // Output buffer (pre-allocate at least len(in) to reduce re-allocation). + out := make([]byte, 0, len(in)) + + // Current scan position + i := 0 + for { + // Find the next occurrence of `"field":` starting from i. + idx := bytes.Index(in[i:], pattern) + if idx == -1 { + // No more occurrences; copy everything left to output. + out = append(out, in[i:]...) + break } + absIdx := i + idx // absolute index of the match in `in` + // 1. Copy everything *before* the match to output. + out = append(out, in[i:absIdx]...) + + // 2. Copy the `"field":` pattern itself to output. + out = append(out, pattern...) + // Advance i past `"field":` + i = absIdx + len(pattern) + + // 3. Preserve any whitespace right after the colon in the output. + for i < len(in) && isWhitespace(in[i]) { + out = append(out, in[i]) + i++ + } + + // 4. If the next character is not `{`, nothing to bracket. Continue scanning. + if i >= len(in) || in[i] != '{' { + continue + } + + // 5. Brace matching. If we find a matching `}`, we bracket the substring. + braceStart := i braceCount := 0 - end := start + len(find) - for i := end; i < len(str); i++ { - if str[i] == '{' { + matchFound := false + + for j := i; j < len(in); j++ { + if in[j] == '{' { braceCount++ - } else if str[i] == '}' { + } else if in[j] == '}' { + braceCount-- if braceCount == 0 { - end = i + 1 + // Found the matching closing brace at j + // Write `[ { ... } ]` to output + out = append(out, '[') + out = append(out, in[braceStart:j+1]...) + out = append(out, ']') + + // Advance i to the char after `}` + i = j + 1 + matchFound = true break } - braceCount-- } } - beforeB := str[:start+len(find)-1] // Adjust to include '{' - afterB := str[end:] // after "}" - objectB := str[start+len(find)-1 : end] // Adjust to start from '{' - return beforeB + "[" + objectB + "]" + afterB, strings.Contains(str, find) - } - - str := strIn - for { - var more bool - str, more = convertToArray(field, str) - if !more { + // 6. If unmatched braces, copy the rest as-is and stop. + if !matchFound { + out = append(out, in[braceStart:]...) + i = len(in) break } } - return str + return string(out) +} + +func isWhitespace(c byte) bool { + return c == ' ' || c == '\t' || c == '\n' || c == '\r' } func convertEmptyStrToZero(field, strIn string) string { diff --git a/globals_test.go b/globals_test.go new file mode 100644 index 0000000..7e9b71a --- /dev/null +++ b/globals_test.go @@ -0,0 +1,211 @@ +package sdk + +import ( + "strings" + "testing" +) + +// TestConvertObjectToArray tests the convertObjectToArray function using +// a range of table-driven test cases. +func TestConvertObjectToArray(t *testing.T) { + tests := []struct { + name string + field string + input string + want string + }{ + { + name: "field not present", + field: "myField", + input: `{"someOtherField": {"key":"val"}}`, + // Nothing changes because "myField" is not found: + want: `{"someOtherField": {"key":"val"}}`, + }, + { + name: "single field occurrence", + field: "myField", + input: `{"myField": {"key": "val"}, "anotherField": 42}`, + // The "myField" object becomes an array: + want: `{"myField": [{"key": "val"}], "anotherField": 42}`, + }, + { + name: "multiple occurrences (top-level)", + field: "myField", + input: ` +{ + "myField": { + "one": 1 + }, + "someOther": "value", + "myField": { + "two": 2 + } +}`, + // Both "myField" occurrences become arrays: + want: ` +{ + "myField": [{ + "one": 1 + }], + "someOther": "value", + "myField": [{ + "two": 2 + }] +}`, + }, + { + name: "spaces/newlines around braces", + field: "myField", + input: `{ + "myField": { + "deep":"structure" + } +}`, + // This code looks only for `"myField": {` exactly. + // Because of extra spaces after "myField" and around braces, + // it won't match exactly unless your JSON is precisely `"myField": {`. + // But let's pretend it matches; the code won't handle extra spaces + // unless you adjust it. For demonstration, assume the spacing is not a problem. + want: `{ + "myField": [{ + "deep":"structure" + }] +}`, + }, + { + name: "nested object, same field name deeper inside", + field: "myField", + input: `{ + "outerField": { + "myField": {"innerKey": 123} + }, + "myField": {"rootKey": "rootVal"} +}`, + // Only the top-level "myField" direct match is turned into an array + // in each pass. The nested one is also found eventually because + // the code scans the full string. Expect both occurrences to be changed. + want: `{ + "outerField": { + "myField": [{"innerKey": 123}] + }, + "myField": [{"rootKey": "rootVal"}] +}`, + }, + { + name: "empty input", + field: "myField", + input: ``, + want: ``, + }, + { + name: "invalid JSON (unmatched braces)", + field: "myField", + // This is obviously malformed JSON. The function will do naive brace + // matching and might produce unexpected results. This tests how it behaves. + input: `{"myField": { "a": { "b": 1 }`, + // The function may or may not gracefully handle this. Expect some naive output. + // For demonstration, we show the likely naive replacement (the code might not find a + // closing brace at all and just return the input or partially replaced string). + // You can adjust expected output to match actual behavior if needed. + want: `{"myField": { "a": { "b": 1 }`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := convertObjectToArray(tt.field, tt.input) + g := strings.ReplaceAll(got, " ", "") + w := strings.ReplaceAll(tt.want, " ", "") + if g != w { + t.Errorf("convertObjectToArray(%q, %q) = \n%s\n want: \n%s", + tt.field, tt.input, g, w) + } + }) + } +} + +// func BenchmarkConvertObjectToArray(b *testing.B) { +// // Here’s a sample input. Make it big or complex if you want +// // to stress-test the function. +// // You could even generate a large JSON string programmatically. +// input := `{ +// "myField": { +// "a": 1 +// }, +// "otherField": "someValue", +// "myField": { +// "b": 2 +// } +// }` + +// // The field we are looking for +// fieldName := "myField" + +// // Reset the timer just before the benchmark loop +// // (sometimes you do any one-time setup first). +// b.ResetTimer() + +// for i := 0; i < b.N; i++ { +// // We don't care about the result in the benchmark; +// // we just want to measure how long it takes. +// _ = convertObjectToArray(fieldName, input) +// } +// } + +// func BenchmarkConvertObjectToArray2(b *testing.B) { +// // Create a somewhat large JSON string with multiple occurrences. +// var input bytes.Buffer +// input.WriteString(`{"outer":true`) +// for i := 0; i < 2000; i++ { +// input.WriteString(`,"myField":{"index":`) +// // Instead of string(i + '0'), use strconv.Itoa(i) +// input.WriteString(strconv.Itoa(i)) +// input.WriteString(`}`) +// } +// input.WriteString(`}`) + +// field := "myField" +// data := input.String() + +// b.ResetTimer() +// for i := 0; i < b.N; i++ { +// _ = convertObjectToArray2(field, data) +// } +// } + +// // Benchmark the original function on a large input. +// func BenchmarkConvertObjectToArrayLarge(b *testing.B) { +// bigJSON := makeLargeTestJSON(50_000) // 50k occurrences of "myField" +// field := "myField" + +// b.ResetTimer() +// for i := 0; i < b.N; i++ { +// _ = convertObjectToArray(field, bigJSON) +// } +// } + +// // Benchmark the new function on a large input. +// func BenchmarkConvertObjectToArray2Large(b *testing.B) { +// bigJSON := makeLargeTestJSON(50_000) // 50k occurrences of "myField" +// field := "myField" + +// b.ResetTimer() +// for i := 0; i < b.N; i++ { +// _ = convertObjectToArray2(field, bigJSON) +// } +// } + +// // makeLargeTestJSON generates a JSON string with `count` occurrences +// // of `"myField": { ... }`. For example, 50k or 100k occurrences. +// func makeLargeTestJSON(count int) string { +// var sb strings.Builder +// sb.Grow(count * 40) // pre-allocate a rough guess of final size + +// sb.WriteString("{\n \"someField\": \"someValue\"") +// for i := 0; i < count; i++ { +// // e.g.: , "myField": { "index": 12345 } +// sb.WriteString(fmt.Sprintf(", \"myField\": { \"index\": %d }", i)) +// } +// sb.WriteString("\n}") +// return sb.String() +// } diff --git a/monitors.go b/monitors.go index b0bde5f..63feb67 100644 --- a/monitors.go +++ b/monitors.go @@ -23,12 +23,6 @@ type MonitorsOptions struct { Undelete bool `json:"undelete,omitempty"` Remove bool `json:"remove,omitempty"` Staged bool `json:"staged,omitempty"` - Watch bool `json:"watch,omitempty"` - Watchlist string `json:"watchlist,omitempty"` - Commands string `json:"commands,omitempty"` - BatchSize uint64 `json:"batchSize,omitempty"` - RunCount uint64 `json:"runCount,omitempty"` - Sleep float64 `json:"sleep,omitempty"` RenderCtx *output.RenderCtx `json:"-"` Globals } diff --git a/monitors_internal.go b/monitors_internal.go index bd65137..657b10d 100644 --- a/monitors_internal.go +++ b/monitors_internal.go @@ -30,12 +30,6 @@ type monitorsOptionsInternal struct { List bool `json:"list,omitempty"` Count bool `json:"count,omitempty"` Staged bool `json:"staged,omitempty"` - Watch bool `json:"watch,omitempty"` - Watchlist string `json:"watchlist,omitempty"` - Commands string `json:"commands,omitempty"` - BatchSize uint64 `json:"batchSize,omitempty"` - RunCount uint64 `json:"runCount,omitempty"` - Sleep float64 `json:"sleep,omitempty"` RenderCtx *output.RenderCtx `json:"-"` Globals } @@ -121,12 +115,6 @@ func (opts *MonitorsOptions) toInternal() *monitorsOptionsInternal { Undelete: opts.Undelete, Remove: opts.Remove, Staged: opts.Staged, - Watch: opts.Watch, - Watchlist: opts.Watchlist, - Commands: opts.Commands, - BatchSize: opts.BatchSize, - RunCount: opts.RunCount, - Sleep: opts.Sleep, RenderCtx: opts.RenderCtx, Globals: opts.Globals, } diff --git a/python/CONTRIBUTING.md b/python/CONTRIBUTING.md index b499ee4..3940e5a 100644 --- a/python/CONTRIBUTING.md +++ b/python/CONTRIBUTING.md @@ -20,7 +20,7 @@ ## Did you make a formatting or cosmetic change? -- We use an automated formatters, therefor formatting-only changes will generally be closed without merging. +- We use an automated formatters, therefore formatting-only changes will generally be closed without merging. ## Would do have a feature request? diff --git a/python/src/_monitors.py b/python/src/_monitors.py index 998a599..eac0a5d 100644 --- a/python/src/_monitors.py +++ b/python/src/_monitors.py @@ -19,12 +19,6 @@ "list": {"hotkey": "-l", "type": "switch"}, "count": {"hotkey": "-c", "type": "switch"}, "staged": {"hotkey": "-S", "type": "switch"}, - "watch": {"hotkey": "-w", "type": "switch"}, - "watchlist": {"hotkey": "-a", "type": "flag"}, - "commands": {"hotkey": "-d", "type": "flag"}, - "batchSize": {"hotkey": "-b", "type": "flag"}, - "runCount": {"hotkey": "-u", "type": "flag"}, - "sleep": {"hotkey": "-s", "type": "flag"}, "chain": {"hotkey": "", "type": "flag"}, "noHeader": {"hotkey": "", "type": "switch"}, "cache": {"hotkey": "-o", "type": "switch"}, diff --git a/services/service.go b/services/service.go index f43a453..e714082 100644 --- a/services/service.go +++ b/services/service.go @@ -102,10 +102,10 @@ func getApiUrl() string { func findAvailablePort(preferred []string) string { for _, port := range preferred { - if listener, err := net.Listen("tcp", ":"+port); err == nil { - defer listener.Close() - return port + if !isPortAvailable(port) { + continue } + return port } return "0" } diff --git a/slurp.go b/slurp.go index 3bf604b..75e4d58 100644 --- a/slurp.go +++ b/slurp.go @@ -149,7 +149,6 @@ type SlurpSource int const ( NoSS SlurpSource = 0 SSEtherscan = 1 << iota - SSKey SSCovalent SSAlchemy ) @@ -162,13 +161,12 @@ func (v SlurpSource) String() string { var m = map[SlurpSource]string{ SSEtherscan: "etherscan", - SSKey: "key", SSCovalent: "covalent", SSAlchemy: "alchemy", } var ret []string - for _, val := range []SlurpSource{SSEtherscan, SSKey, SSCovalent, SSAlchemy} { + for _, val := range []SlurpSource{SSEtherscan, SSCovalent, SSAlchemy} { if v&val != 0 { ret = append(ret, m[val]) } @@ -187,8 +185,6 @@ func enumFromSlurpSource(values []string) (SlurpSource, error) { switch val { case "etherscan": result |= SSEtherscan - case "key": - result |= SSKey case "covalent": result |= SSCovalent case "alchemy": diff --git a/typescript/src/paths/monitors.ts b/typescript/src/paths/monitors.ts index b7559d7..1596382 100644 --- a/typescript/src/paths/monitors.ts +++ b/typescript/src/paths/monitors.ts @@ -9,7 +9,7 @@ */ import * as ApiCallers from '../lib/api_callers'; -import { address, Count, float64, Message, Monitor, MonitorClean, uint64 } from '../types'; +import { address, Count, Message, Monitor, MonitorClean } from '../types'; export function getMonitors( parameters?: { @@ -21,12 +21,6 @@ export function getMonitors( list?: boolean; count?: boolean; staged?: boolean; - watch?: boolean; - watchlist?: string; - commands?: string; - batchSize?: uint64; - runCount?: uint64; - sleep?: float64; fmt?: string; chain: string; noHeader?: boolean; diff --git a/typescript/src/paths/slurp.ts b/typescript/src/paths/slurp.ts index 8471bf9..12b43ea 100644 --- a/typescript/src/paths/slurp.ts +++ b/typescript/src/paths/slurp.ts @@ -18,7 +18,7 @@ export function getSlurp( parts?: string[]; appearances?: boolean; articulate?: boolean; - source?: 'etherscan' | 'key' | 'covalent' | 'alchemy'; + source?: 'etherscan' | 'covalent' | 'alchemy'; count?: boolean; page?: uint64; pageId?: string; diff --git a/updater_test.go b/updater_test.go index 379ab74..3e22490 100644 --- a/updater_test.go +++ b/updater_test.go @@ -4,8 +4,6 @@ import ( "os" "testing" "time" - - "github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/walk" ) func TestNeedsUpdateWithFile(t *testing.T) { @@ -112,403 +110,3 @@ func fileModTime(path string) int64 { } return info.ModTime().Unix() } - -func folderSize(path string) int64 { - var totalSize int64 - err := walk.ForEveryFileInFolder(path, func(filePath string, _ any) (bool, error) { - info, err := os.Stat(filePath) - if err != nil { - return false, err - } - totalSize += info.Size() - return true, nil - }, nil) - if err != nil { - return 0 - } - return totalSize -} - -/* - -// TODO: THIS CAN ALMOST CERTAINLY BE DELETED -func TestNewUpdaterWithPaths(t *testing.T) { - items := []UpdaterItem{ - {Path: "path1", Type: File}, - {Path: "path2", Type: File}, - } - u, err := NewUpdater("test", items) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if len(u.Items) != 2 { - t.Errorf("expected 2 items, got %d", len(u.Items)) - } - if u.Items[0].Type != File || u.Items[1].Type != File { - t.Errorf("expected UpdateType to be File, got %v and %v", u.Items[0].Type, u.Items[1].Type) - } - if u.LastTimeStamp == 0 { - t.Errorf("expected LastTimeStamp to be non-zero, got %d", u.LastTimeStamp) - } -} - -func TestNewUpdaterWithDuration(t *testing.T) { - duration := 10 * time.Second - items := []UpdaterItem{ - {Duration: duration, Type: Timer}, - } - u, err := NewUpdater("test", items) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if len(u.Items) != 1 { - t.Errorf("expected 1 item, got %d", len(u.Items)) - } - if u.Items[0].Type != Timer { - t.Errorf("expected UpdateType to be Timer, got %v", u.Items[0].Type) - } - if u.Items[0].Duration != duration { - t.Errorf("expected duration %v, got %v", duration, u.Items[0].Duration) - } - if u.LastTimeStamp == 0 { - t.Errorf("expected LastTimeStamp to be non-zero, got %d", u.LastTimeStamp) - } -} - -func TestNewUpdaterWithPathsAndDuration(t *testing.T) { - duration := 15 * time.Second - items := []UpdaterItem{ - {Path: "path1", Type: Folder, Duration: duration}, - } - u, err := NewUpdater("test", items) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if len(u.Items) != 1 { - t.Errorf("expected 1 item, got %d", len(u.Items)) - } - if u.Items[0].Path != "path1" { - t.Errorf("expected path 'path1', got %s", u.Items[0].Path) - } - if u.Items[0].Type != Folder { - t.Errorf("expected UpdateType to be Folder, got %v", u.Items[0].Type) - } - if u.Items[0].Duration != duration { - t.Errorf("expected duration %v, got %v", duration, u.Items[0].Duration) - } - if u.LastTimeStamp == 0 { - t.Errorf("expected LastTimeStamp to be non-zero, got %d", u.LastTimeStamp) - } -} - -func TestNeedsUpdateWithDuration(t *testing.T) { - duration := 10 * time.Second - items := []UpdaterItem{ - {Duration: duration, Type: Timer}, - } - u, err := NewUpdater("test", items) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - u.LastTimeStamp = time.Now().Add(-20 * time.Second).Unix() - updatedUpdater, needsUpdate, err := u.NeedsUpdate() - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if !needsUpdate { - t.Errorf("expected needsUpdate to be true") - } - if updatedUpdater.LastTimeStamp <= u.LastTimeStamp { - t.Errorf("expected updated LastTimeStamp to be greater than original") - } -} - -func TestSetChain(t *testing.T) { - items := []UpdaterItem{ - {Path: "/oldChain/path1", Type: File}, - {Path: "/oldChain/path2", Type: File}, - } - u, err := NewUpdater("test", items) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - u.SetChain("oldChain", "newChain") - expectedPaths := []string{"/newChain/path1", "/newChain/path2"} - for i, item := range u.Items { - if item.Path != expectedPaths[i] { - t.Errorf("expected path %s, got %s", expectedPaths[i], item.Path) - } - } -} - -func TestReset(t *testing.T) { - items := []UpdaterItem{ - {Path: "path1", Type: File}, - } - u, err := NewUpdater("test", items) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - u.LastTimeStamp = time.Now().Unix() - u.Reset() - if u.LastTimeStamp != 0 { - t.Errorf("expected LastTimeStamp to be reset to 0, got %d", u.LastTimeStamp) - } - if u.LastTotalSize != 0 { - t.Errorf("expected LastTotalSize to be reset to 0, got %d", u.LastTotalSize) - } -} - -func TestNewUpdaterWithSize(t *testing.T) { - items := []UpdaterItem{ - {Path: "path1", Type: FileSize}, - } - u, err := NewUpdater("test", items) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if len(u.Items) != 1 { - t.Errorf("expected 1 item, got %d", len(u.Items)) - } - if u.Items[0].Type != FileSize { - t.Errorf("expected UpdateType to be FileSize, got %v", u.Items[0].Type) - } - if u.LastTimeStamp != -1 { - t.Errorf("expected LastTimeStamp to be -1, got %d", u.LastTimeStamp) - } - if u.LastTotalSize != -1 { - t.Errorf("expected LastTotalSize to be -1, got %d", u.LastTotalSize) - } -} - -func TestNeedsUpdateWithShortDuration(t *testing.T) { - duration := 1 * time.Second - items := []UpdaterItem{ - {Duration: duration, Type: Timer}, - } - u, err := NewUpdater("test", items) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - // Set LastTimeStamp to a past time - u.LastTimeStamp = time.Now().Add(-2 * time.Second).Unix() - - // Wait for a short duration to ensure the timer condition is met - time.Sleep(2 * time.Second) - - updatedUpdater, needsUpdate, err := u.NeedsUpdate() - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if !needsUpdate { - t.Errorf("expected needsUpdate to be true") - } - if updatedUpdater.LastTimeStamp <= u.LastTimeStamp { - t.Errorf("expected updated LastTimeStamp to be greater than original") - } -} - -func TestNeedsUpdateWithSize(t *testing.T) { - // Create a temporary file - tempFile, err := ioutil.TempFile("", "testfile") - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - defer os.Remove(tempFile.Name()) // Clean up - - // Write some data to the file to set its size - if _, err := tempFile.Write([]byte("initial data")); err != nil { - t.Fatalf("unexpected error: %v", err) - } - - items := []UpdaterItem{ - {Path: tempFile.Name(), Type: FileSize}, - } - u, err := NewUpdater("test", items) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - // Set LastTotalSize to the current size of the file - u.LastTotalSize = fileSize(tempFile.Name()) - - // Write more data to the file to increase its size - if _, err := tempFile.Write([]byte(" more data")); err != nil { - t.Fatalf("unexpected error: %v", err) - } - - updatedUpdater, needsUpdate, err := u.NeedsUpdate() - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if !needsUpdate { - t.Errorf("expected needsUpdate to be true") - } - if updatedUpdater.LastTotalSize <= u.LastTotalSize { - t.Errorf("expected updated LastTotalSize to be greater than original") - } -} - -func TestNeedsUpdateWithError(t *testing.T) { - // Create a temporary file - tempFile, err := ioutil.TempFile("", "testfile") - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - defer os.Remove(tempFile.Name()) // Clean up - - // Write some data to the file to set its size - if _, err := tempFile.Write([]byte("initial data")); err != nil { - t.Fatalf("unexpected error: %v", err) - } - - items := []UpdaterItem{ - {Path: tempFile.Name(), Type: File}, - } - u, err := NewUpdater("test", items) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - // Simulate an error by setting an invalid path - u.Items[0].Path = "/invalid/path" - - _, _, err = u.NeedsUpdate() - if err == nil { - t.Errorf("expected an error, got nil") - } -} - -func TestNeedsUpdateWithFolderSize(t *testing.T) { - // Create a temporary directory - tempDir, err := ioutil.TempDir("", "testdir") - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - defer os.RemoveAll(tempDir) // Clean up - - // Create a temporary file in the directory - tempFile, err := ioutil.TempFile(tempDir, "testfile") - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - // Write some data to the file to set its size - if _, err := tempFile.Write([]byte("initial data")); err != nil { - t.Fatalf("unexpected error: %v", err) - } - - items := []UpdaterItem{ - {Path: tempDir, Type: FolderSize}, - } - u, err := NewUpdater("test", items) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - // Set LastTotalSize to the current size of the folder - u.LastTotalSize = folderSize(tempDir) - - // Write more data to the file to increase its size - if _, err := tempFile.Write([]byte(" more data")); err != nil { - t.Fatalf("unexpected error: %v", err) - } - - updatedUpdater, needsUpdate, err := u.NeedsUpdate() - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if !needsUpdate { - t.Errorf("expected needsUpdate to be true") - } - if updatedUpdater.LastTotalSize <= u.LastTotalSize { - t.Errorf("expected updated LastTotalSize to be greater than original") - } -} - -func TestNeedsUpdateWithSizeAndFolderSize(t *testing.T) { - // Create a temporary file - tempFile, err := ioutil.TempFile("", "testfile") - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - defer os.Remove(tempFile.Name()) // Clean up - - // Write some data to the file to set its size - if _, err := tempFile.Write([]byte("initial data")); err != nil { - t.Fatalf("unexpected error: %v", err) - } - - // Create a temporary directory - tempDir, err := ioutil.TempDir("", "testdir") - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - defer os.RemoveAll(tempDir) // Clean up - - // Create a temporary file in the directory - tempFileInDir, err := ioutil.TempFile(tempDir, "testfile") - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - // Write some data to the file in the directory to set its size - if _, err := tempFileInDir.Write([]byte("initial data")); err != nil { - t.Fatalf("unexpected error: %v", err) - } - - items := []UpdaterItem{ - {Path: tempFile.Name(), Type: FileSize}, - {Path: tempDir, Type: FolderSize}, - } - u, err := NewUpdater("test", items) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - // Set LastTotalSize to the current size of the file and folder - u.LastTotalSize = fileSize(tempFile.Name()) + folderSize(tempDir) - - // Write more data to the file to increase its size - if _, err := tempFile.Write([]byte(" more data")); err != nil { - t.Fatalf("unexpected error: %v", err) - } - - // Write more data to the file in the directory to increase its size - if _, err := tempFileInDir.Write([]byte(" more data")); err != nil { - t.Fatalf("unexpected error: %v", err) - } - - updatedUpdater, needsUpdate, err := u.NeedsUpdate() - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if !needsUpdate { - t.Errorf("expected needsUpdate to be true") - } - if updatedUpdater.LastTotalSize <= u.LastTotalSize { - t.Errorf("expected updated LastTotalSize to be greater than original") - } - - // Verify that LastTotalSize is updated correctly - if updatedUpdater.LastTotalSize != fileSize(tempFile.Name())+folderSize(tempDir) { - t.Errorf("expected LastTotalSize to be updated correctly") - } - - // Check for unexpected resets - if updatedUpdater.LastTotalSize == 0 { - t.Errorf("unexpected reset of LastTotalSize") - } -} - -// Helper function to get the size of a file -func fileSize(path string) int64 { - info, err := os.Stat(path) - if err != nil { - return 0 - } - return info.Size() -} - -*/ \ No newline at end of file