From 3bf9e25002e1a099c2ca7dbfa5a7d548d918edfe Mon Sep 17 00:00:00 2001 From: Kelvin Mwinuka Date: Fri, 5 Apr 2024 23:05:23 +0800 Subject: [PATCH 1/8] Fixed race conditions in acl module tests --- Makefile | 3 + coverage/coverage.out | 602 +++++++++++++++---------------- pkg/modules/acl/commands_test.go | 13 +- 3 files changed, 310 insertions(+), 308 deletions(-) diff --git a/Makefile b/Makefile index ecc178b1..61b39bc0 100644 --- a/Makefile +++ b/Makefile @@ -9,3 +9,6 @@ run: test: go clean -testcache && go test ./... -coverprofile coverage/coverage.out + +test-race: + go clean -testcache && go test ./... --race \ No newline at end of file diff --git a/coverage/coverage.out b/coverage/coverage.out index 3c47eab8..50823bb8 100644 --- a/coverage/coverage.out +++ b/coverage/coverage.out @@ -1358,307 +1358,6 @@ github.com/echovault/echovault/pkg/modules/generic/utils.go:107.3,109.17 3 1 github.com/echovault/echovault/pkg/modules/generic/utils.go:109.17,111.4 1 1 github.com/echovault/echovault/pkg/modules/generic/utils.go:112.3,113.53 2 1 github.com/echovault/echovault/pkg/modules/generic/utils.go:115.10,116.95 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:26.108,27.18 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:28.10,29.54 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:30.9,31.34 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:32.9,33.72 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:37.33,45.60 1 0 -github.com/echovault/echovault/pkg/modules/connection/commands.go:45.60,47.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:30.105,32.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:32.16,34.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:36.2,38.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:38.33,41.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:43.2,43.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:43.52,45.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:46.2,48.63 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:48.63,50.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:52.2,52.57 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:55.110,57.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:57.16,59.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:61.2,64.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:64.9,66.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:68.2,68.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:68.33,70.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:72.2,72.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:72.52,74.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:75.2,78.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:78.9,80.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:82.2,82.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:82.40,84.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:86.2,86.57 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:89.110,91.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:91.16,93.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:95.2,99.24 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:99.24,101.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:103.2,103.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:103.33,105.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:107.2,107.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:107.52,109.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:110.2,113.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:113.9,115.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:118.2,118.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:118.40,120.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:123.2,123.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:123.51,125.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:127.2,130.15 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:130.15,132.43 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:132.43,135.4 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:136.3,136.20 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:140.2,140.18 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:140.18,142.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:147.2,151.17 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:151.17,153.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:155.2,155.13 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:155.13,158.18 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:158.18,160.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:160.9,162.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:165.2,165.19 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:168.108,170.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:170.16,172.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:174.2,177.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:177.9,179.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:181.2,181.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:181.33,183.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:185.2,185.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:185.51,187.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:188.2,191.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:191.9,193.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:195.2,195.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:195.40,197.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:199.2,200.55 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:200.55,202.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:204.2,204.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:207.109,209.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:209.16,211.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:213.2,217.24 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:217.24,219.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:221.2,221.30 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:221.30,223.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:225.2,225.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:225.33,227.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:229.2,229.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:229.51,231.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:232.2,235.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:235.9,237.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:239.2,239.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:239.40,241.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:243.2,243.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:243.34,244.64 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:244.64,246.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:247.3,247.43 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:250.2,250.66 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:250.66,252.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:253.2,253.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:256.108,258.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:258.16,260.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:262.2,266.9 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:266.9,268.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:270.2,272.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:272.33,274.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:276.2,276.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:276.51,278.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:279.2,282.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:282.9,284.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:286.2,286.9 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:287.10,287.10 0 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:289.17,291.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:291.34,292.26 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:292.26,293.10 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:295.4,295.43 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:295.43,298.5 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:300.17,302.39 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:302.39,303.26 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:303.26,304.10 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:306.4,306.43 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:306.43,309.5 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:313.2,313.61 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:313.61,315.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:317.2,317.55 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:317.55,319.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:321.2,321.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:324.109,326.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:326.16,328.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:330.2,335.116 5 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:335.116,337.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:339.2,339.75 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:339.75,341.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:343.2,343.54 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:343.54,345.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:346.2,349.16 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:349.16,351.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:352.2,357.33 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:357.33,359.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:361.2,361.19 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:362.14,364.24 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:364.24,366.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:366.9,366.32 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:366.32,368.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:369.15,371.24 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:371.24,373.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:373.9,373.32 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:373.32,375.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:378.2,378.16 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:378.16,380.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:382.2,382.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:385.106,387.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:387.16,389.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:391.2,393.31 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:393.31,395.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:397.2,399.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:399.33,400.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:401.17,402.61 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:403.11,404.62 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:404.62,406.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:407.4,407.68 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:407.68,409.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:411.8,412.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:412.52,414.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:416.2,421.9 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:421.9,423.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:425.2,425.73 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:425.73,427.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:428.2,428.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:431.109,433.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:433.16,435.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:437.2,441.31 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:441.31,443.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:445.2,445.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:445.33,446.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:447.17,448.61 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:449.11,450.62 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:450.62,452.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:453.4,454.68 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:454.68,456.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:458.8,459.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:459.52,461.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:462.3,462.35 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:465.2,469.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:469.9,471.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:473.2,473.73 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:473.73,475.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:476.2,476.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:479.104,481.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:481.16,483.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:485.2,487.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:487.33,489.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:491.2,491.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:491.51,493.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:494.2,497.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:497.9,499.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:501.2,501.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:502.10,503.60 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:503.60,505.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:506.3,506.54 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:507.14,508.70 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:508.70,510.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:511.3,511.64 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:515.33,635.2 1 0 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:22.51,23.18 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:23.18,25.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:26.2,26.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:29.49,30.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:30.19,32.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:33.2,33.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:36.50,37.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:37.19,39.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:40.2,40.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:43.52,44.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:44.19,46.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:47.2,47.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:50.52,51.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:51.19,53.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:54.2,54.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:57.50,58.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:58.19,60.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:61.2,61.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:64.51,65.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:65.19,67.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:68.2,68.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:71.50,72.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:72.19,74.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:75.2,75.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:78.51,79.18 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:79.18,81.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:82.2,82.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:85.51,86.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:86.19,88.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:89.2,89.38 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:29.115,35.29 4 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:35.29,36.54 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:36.54,42.42 4 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:42.42,44.5 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:46.4,49.12 3 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:52.3,52.36 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:52.36,59.43 5 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:59.43,61.5 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:63.4,65.21 2 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:69.2,71.25 2 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:74.109,78.35 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:78.35,79.65 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:79.65,80.41 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:80.41,82.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:83.4,83.12 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:85.3,85.13 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:88.2,88.51 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:91.110,92.18 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:93.9,98.36 4 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:98.36,99.66 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:99.66,100.52 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:100.52,104.6 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:105.5,105.13 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:107.4,108.14 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:110.3,111.26 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:113.9,117.45 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:117.45,119.4 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:120.3,120.42 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:120.42,124.37 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:124.37,125.67 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:125.67,126.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:126.53,127.59 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:127.59,131.8 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:133.6,133.14 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:135.5,135.54 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:135.54,138.6 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:140.9,140.50 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:140.50,144.37 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:144.37,145.67 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:145.67,146.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:146.53,148.24 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:148.24,151.8 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:153.6,153.14 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:155.5,155.33 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:155.33,158.6 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:160.9,160.49 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:160.49,164.37 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:164.37,165.67 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:165.67,166.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:166.53,167.55 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:167.55,171.8 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:173.6,173.14 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:175.5,175.50 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:175.50,178.6 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:180.9,182.4 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:183.3,184.26 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:185.10,186.54 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:190.103,192.2 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:194.33,202.60 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:202.60,202.86 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:211.60,213.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:221.62,221.88 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:230.62,230.88 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:240.62,240.88 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:251.60,253.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:254.113,255.49 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:255.49,257.6 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:258.5,258.45 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:267.60,269.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:270.113,272.18 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:272.18,274.6 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:275.5,275.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:284.60,286.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:287.113,288.47 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:288.47,290.6 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:291.5,291.45 1 0 github.com/echovault/echovault/pkg/modules/hash/commands.go:31.105,33.16 2 1 github.com/echovault/echovault/pkg/modules/hash/commands.go:33.16,35.3 1 1 github.com/echovault/echovault/pkg/modules/hash/commands.go:37.2,40.25 3 1 @@ -1966,6 +1665,307 @@ github.com/echovault/echovault/pkg/modules/pubsub/commands.go:188.101,190.5 1 0 github.com/echovault/echovault/pkg/modules/pubsub/commands.go:200.62,200.88 1 0 github.com/echovault/echovault/pkg/modules/pubsub/commands.go:209.62,209.88 1 0 github.com/echovault/echovault/pkg/modules/pubsub/commands.go:219.62,219.85 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:30.105,32.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:32.16,34.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:36.2,38.33 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:38.33,41.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:43.2,43.52 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:43.52,45.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:46.2,48.63 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:48.63,50.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:52.2,52.57 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:55.110,57.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:57.16,59.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:61.2,64.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:64.9,66.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:68.2,68.33 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:68.33,70.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:72.2,72.52 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:72.52,74.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:75.2,78.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:78.9,80.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:82.2,82.40 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:82.40,84.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:86.2,86.57 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:89.110,91.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:91.16,93.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:95.2,99.24 4 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:99.24,101.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:103.2,103.33 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:103.33,105.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:107.2,107.52 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:107.52,109.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:110.2,113.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:113.9,115.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:118.2,118.40 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:118.40,120.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:123.2,123.51 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:123.51,125.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:127.2,130.15 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:130.15,132.43 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:132.43,135.4 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:136.3,136.20 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:140.2,140.18 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:140.18,142.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:147.2,151.17 4 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:151.17,153.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:155.2,155.13 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:155.13,158.18 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:158.18,160.4 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:160.9,162.4 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:165.2,165.19 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:168.108,170.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:170.16,172.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:174.2,177.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:177.9,179.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:181.2,181.33 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:181.33,183.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:185.2,185.51 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:185.51,187.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:188.2,191.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:191.9,193.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:195.2,195.40 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:195.40,197.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:199.2,200.55 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:200.55,202.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:204.2,204.42 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:207.109,209.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:209.16,211.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:213.2,217.24 4 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:217.24,219.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:221.2,221.30 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:221.30,223.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:225.2,225.33 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:225.33,227.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:229.2,229.51 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:229.51,231.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:232.2,235.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:235.9,237.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:239.2,239.40 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:239.40,241.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:243.2,243.34 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:243.34,244.64 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:244.64,246.4 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:247.3,247.43 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:250.2,250.66 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:250.66,252.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:253.2,253.42 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:256.108,258.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:258.16,260.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:262.2,266.9 4 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:266.9,268.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:270.2,272.33 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:272.33,274.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:276.2,276.51 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:276.51,278.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:279.2,282.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:282.9,284.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:286.2,286.9 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:287.10,287.10 0 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:289.17,291.34 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:291.34,292.26 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:292.26,293.10 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:295.4,295.43 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:295.43,298.5 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:300.17,302.39 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:302.39,303.26 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:303.26,304.10 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:306.4,306.43 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:306.43,309.5 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:313.2,313.61 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:313.61,315.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:317.2,317.55 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:317.55,319.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:321.2,321.42 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:324.109,326.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:326.16,328.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:330.2,335.116 5 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:335.116,337.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:339.2,339.75 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:339.75,341.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:343.2,343.54 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:343.54,345.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:346.2,349.16 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:349.16,351.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:352.2,357.33 4 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:357.33,359.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:361.2,361.19 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:362.14,364.24 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:364.24,366.4 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:366.9,366.32 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:366.32,368.4 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:369.15,371.24 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:371.24,373.4 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:373.9,373.32 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:373.32,375.4 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:378.2,378.16 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:378.16,380.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:382.2,382.42 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:385.106,387.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:387.16,389.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:391.2,393.31 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:393.31,395.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:397.2,399.33 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:399.33,400.34 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:401.17,402.61 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:403.11,404.62 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:404.62,406.5 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:407.4,407.68 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:407.68,409.5 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:411.8,412.52 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:412.52,414.4 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:416.2,421.9 4 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:421.9,423.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:425.2,425.73 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:425.73,427.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:428.2,428.42 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:431.109,433.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:433.16,435.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:437.2,441.31 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:441.31,443.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:445.2,445.33 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:445.33,446.34 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:447.17,448.61 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:449.11,450.62 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:450.62,452.5 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:453.4,454.68 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:454.68,456.5 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:458.8,459.52 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:459.52,461.4 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:462.3,462.35 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:465.2,469.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:469.9,471.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:473.2,473.73 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:473.73,475.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:476.2,476.42 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:479.104,481.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:481.16,483.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:485.2,487.33 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:487.33,489.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:491.2,491.51 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:491.51,493.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:494.2,497.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:497.9,499.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:501.2,501.33 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:502.10,503.60 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:503.60,505.4 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:506.3,506.54 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:507.14,508.70 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:508.70,510.4 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:511.3,511.64 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:515.33,635.2 1 0 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:22.51,23.18 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:23.18,25.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:26.2,26.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:29.49,30.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:30.19,32.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:33.2,33.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:36.50,37.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:37.19,39.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:40.2,40.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:43.52,44.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:44.19,46.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:47.2,47.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:50.52,51.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:51.19,53.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:54.2,54.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:57.50,58.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:58.19,60.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:61.2,61.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:64.51,65.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:65.19,67.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:68.2,68.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:71.50,72.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:72.19,74.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:75.2,75.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:78.51,79.18 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:79.18,81.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:82.2,82.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:85.51,86.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:86.19,88.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:89.2,89.38 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:26.108,27.18 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:28.10,29.54 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:30.9,31.34 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:32.9,33.72 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:37.33,45.60 1 0 +github.com/echovault/echovault/pkg/modules/connection/commands.go:45.60,47.5 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:29.115,35.29 4 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:35.29,36.54 1 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:36.54,42.42 4 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:42.42,44.5 1 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:46.4,49.12 3 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:52.3,52.36 1 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:52.36,59.43 5 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:59.43,61.5 1 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:63.4,65.21 2 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:69.2,71.25 2 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:74.109,78.35 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:78.35,79.65 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:79.65,80.41 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:80.41,82.5 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:83.4,83.12 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:85.3,85.13 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:88.2,88.51 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:91.110,92.18 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:93.9,98.36 4 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:98.36,99.66 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:99.66,100.52 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:100.52,104.6 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:105.5,105.13 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:107.4,108.14 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:110.3,111.26 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:113.9,117.45 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:117.45,119.4 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:120.3,120.42 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:120.42,124.37 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:124.37,125.67 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:125.67,126.53 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:126.53,127.59 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:127.59,131.8 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:133.6,133.14 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:135.5,135.54 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:135.54,138.6 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:140.9,140.50 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:140.50,144.37 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:144.37,145.67 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:145.67,146.53 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:146.53,148.24 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:148.24,151.8 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:153.6,153.14 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:155.5,155.33 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:155.33,158.6 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:160.9,160.49 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:160.49,164.37 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:164.37,165.67 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:165.67,166.53 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:166.53,167.55 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:167.55,171.8 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:173.6,173.14 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:175.5,175.50 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:175.50,178.6 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:180.9,182.4 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:183.3,184.26 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:185.10,186.54 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:190.103,192.2 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:194.33,202.60 1 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:202.60,202.86 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:211.60,213.5 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:221.62,221.88 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:230.62,230.88 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:240.62,240.88 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:251.60,253.5 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:254.113,255.49 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:255.49,257.6 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:258.5,258.45 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:267.60,269.5 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:270.113,272.18 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:272.18,274.6 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:275.5,275.53 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:284.60,286.5 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:287.113,288.47 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:288.47,290.6 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:291.5,291.45 1 0 github.com/echovault/echovault/pkg/modules/set/commands.go:30.108,32.16 2 1 github.com/echovault/echovault/pkg/modules/set/commands.go:32.16,34.3 1 1 github.com/echovault/echovault/pkg/modules/set/commands.go:36.2,40.33 3 1 diff --git a/pkg/modules/acl/commands_test.go b/pkg/modules/acl/commands_test.go index 969b8b83..da8b5577 100644 --- a/pkg/modules/acl/commands_test.go +++ b/pkg/modules/acl/commands_test.go @@ -35,7 +35,7 @@ var mockServer *echovault.EchoVault func init() { bindAddr = "localhost" - port = 7490 + port = 7496 mockServer = setUpServer(bindAddr, port, true, "") @@ -1019,7 +1019,7 @@ func Test_HandleSetUser(t *testing.T) { for i, test := range tests { if test.presetUser != nil { - acl.Users = append(acl.Users, test.presetUser) + acl.AddUsers([]*internal_acl.User{test.presetUser}) } if err = r.WriteArray(test.cmd); err != nil { t.Error(err) @@ -1164,7 +1164,7 @@ func Test_HandleGetUser(t *testing.T) { for _, test := range tests { if test.presetUser != nil { - acl.Users = append(acl.Users, test.presetUser) + acl.AddUsers([]*internal_acl.User{test.presetUser}) } if err = r.WriteArray(test.cmd); err != nil { t.Error(err) @@ -1261,7 +1261,7 @@ func Test_HandleDelUser(t *testing.T) { for _, test := range tests { if test.presetUser != nil { - acl.Users = append(acl.Users, test.presetUser) + acl.AddUsers([]*internal_acl.User{test.presetUser}) } if err = r.WriteArray(test.cmd); err != nil { t.Error(err) @@ -1456,9 +1456,8 @@ func Test_HandleList(t *testing.T) { } for _, test := range tests { - for _, user := range test.presetUsers { - acl.Users = append(acl.Users, user) - } + acl.AddUsers(test.presetUsers) + if err = r.WriteArray(test.cmd); err != nil { t.Error(err) } From 4ae8ff1bb9cef38bb78f871782a7f84a7153759d Mon Sep 17 00:00:00 2001 From: Kelvin Mwinuka Date: Fri, 5 Apr 2024 23:08:49 +0800 Subject: [PATCH 2/8] Added test for data race in go.yml github workflow --- .github/workflows/go.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 25dc25d8..b7d68644 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -29,6 +29,9 @@ jobs: - name: Test run: go test -coverprofile=coverage.out -v ./... + - name: Test for Data Race + run: go test ./... --race + - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v4.0.1 with: From 9df42f2179a8f28ad37465883da932388035ab95 Mon Sep 17 00:00:00 2001 From: Kelvin Mwinuka Date: Fri, 5 Apr 2024 23:23:14 +0800 Subject: [PATCH 3/8] Leverage t.Run in string module tests --- coverage/coverage.out | 1126 +++++++++++++-------------- pkg/modules/string/commands_test.go | 240 +++--- 2 files changed, 700 insertions(+), 666 deletions(-) diff --git a/coverage/coverage.out b/coverage/coverage.out index 50823bb8..7920f91c 100644 --- a/coverage/coverage.out +++ b/coverage/coverage.out @@ -1108,563 +1108,12 @@ github.com/echovault/echovault/pkg/modules/acl/commands.go:578.62,580.7 1 1 github.com/echovault/echovault/pkg/modules/acl/commands.go:589.62,591.7 1 1 github.com/echovault/echovault/pkg/modules/acl/commands.go:603.62,605.7 1 0 github.com/echovault/echovault/pkg/modules/acl/commands.go:614.62,616.7 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:36.104,38.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:38.16,40.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:42.2,48.16 6 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:48.16,50.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:54.2,54.16 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:54.16,55.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:55.34,57.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:57.9,59.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:62.2,62.44 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:62.44,64.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:64.34,66.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:67.3,67.36 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:68.8,68.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:68.51,70.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:70.33,72.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:73.3,73.45 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:74.8,76.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:76.34,79.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:79.9,82.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:84.2,84.16 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:84.16,86.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:87.2,89.76 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:89.76,91.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:94.2,94.28 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:94.28,96.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:98.2,98.17 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:101.105,102.44 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:102.44,104.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:106.2,109.15 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:109.15,110.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:110.29,111.16 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:111.16,117.5 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:122.2,122.30 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:122.30,123.15 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:123.15,128.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:133.2,133.28 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:133.28,134.31 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:134.31,135.52 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:135.52,137.5 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:138.4,139.12 2 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:141.3,141.60 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:141.60,143.4 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:144.3,144.55 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:148.2,148.28 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:148.28,149.58 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:149.58,151.4 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:154.2,154.42 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:157.104,159.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:159.16,161.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:162.2,164.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:164.33,166.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:168.2,169.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:169.16,171.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:172.2,176.51 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:179.105,181.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:181.16,183.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:185.2,188.27 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:188.27,189.31 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:189.31,191.12 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:193.3,193.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:193.33,195.18 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:195.18,197.5 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:198.4,199.12 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:201.3,201.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:203.2,203.15 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:203.15,204.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:204.34,205.14 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:205.14,208.5 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:212.2,212.28 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:212.28,214.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:216.2,218.30 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:218.30,219.24 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:219.24,221.12 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:223.3,223.96 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:226.2,226.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:229.104,231.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:231.16,233.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:234.2,235.27 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:235.27,237.17 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:237.17,239.12 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:241.3,241.13 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:243.2,243.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:246.108,248.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:248.16,250.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:252.2,254.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:254.33,256.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:258.2,258.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:258.51,260.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:261.2,264.31 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:264.31,266.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:268.2,270.30 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:273.111,275.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:275.16,277.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:279.2,281.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:281.33,283.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:285.2,285.52 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:285.52,287.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:288.2,292.31 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:292.31,294.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:296.2,297.46 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:297.46,299.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:301.2,301.47 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:304.104,306.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:306.16,308.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:310.2,314.33 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:314.33,316.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:318.2,318.52 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:318.52,320.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:321.2,325.31 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:325.31,327.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:329.2,330.39 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:330.39,332.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:334.2,334.12 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:334.12,336.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:338.2,338.47 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:341.107,343.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:343.16,345.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:347.2,351.16 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:351.16,353.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:354.2,355.42 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:355.42,357.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:359.2,359.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:359.33,361.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:363.2,363.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:363.51,365.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:366.2,368.19 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:368.19,371.3 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:373.2,375.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:376.12,377.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:377.39,379.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:380.3,380.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:381.12,382.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:382.39,384.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:385.3,385.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:386.12,387.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:387.39,389.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:390.3,390.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:390.39,392.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:393.3,393.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:394.12,395.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:395.39,396.40 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:396.40,398.5 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:399.4,399.47 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:401.3,401.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:402.10,403.71 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:406.2,406.30 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:409.109,411.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:411.16,413.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:415.2,419.16 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:419.16,421.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:422.2,423.44 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:423.44,425.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:427.2,427.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:427.33,429.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:431.2,431.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:431.51,433.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:434.2,436.19 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:436.19,439.3 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:441.2,443.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:444.12,445.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:445.39,447.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:448.3,448.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:449.12,450.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:450.39,452.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:453.3,453.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:454.12,455.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:455.39,457.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:458.3,458.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:458.39,460.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:461.3,461.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:462.12,463.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:463.39,464.40 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:464.40,466.5 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:467.4,467.47 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:469.3,469.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:470.10,471.71 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:474.2,474.30 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:477.33,646.2 1 0 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:22.49,23.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:23.34,25.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:26.2,26.30 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:29.50,30.25 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:30.25,32.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:33.2,34.30 2 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:34.30,35.15 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:35.15,37.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:39.2,39.18 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:42.49,43.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:43.19,45.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:46.2,46.30 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:49.50,50.18 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:50.18,52.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:53.2,53.21 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:56.49,57.18 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:57.18,59.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:60.2,60.21 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:63.53,64.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:64.19,66.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:67.2,67.21 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:70.56,71.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:71.19,73.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:74.2,74.21 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:77.49,78.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:78.19,80.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:81.2,81.21 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:84.52,85.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:85.34,87.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:88.2,88.30 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:91.54,92.34 1 0 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:92.34,94.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:95.2,95.30 1 0 -github.com/echovault/echovault/pkg/modules/generic/utils.go:32.96,33.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:33.19,35.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:36.2,36.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:37.13,39.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:41.12,42.26 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:42.26,44.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:45.3,46.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:48.12,49.26 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:49.26,51.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:52.3,53.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:55.12,56.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:56.19,58.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:59.3,59.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:59.29,61.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:62.3,64.17 3 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:64.17,66.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:67.3,68.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:70.12,71.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:71.19,73.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:74.3,74.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:74.29,76.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:77.3,79.17 3 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:79.17,81.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:82.3,83.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:85.14,86.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:86.19,88.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:89.3,89.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:89.29,91.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:92.3,94.17 3 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:94.17,96.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:97.3,98.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:100.14,101.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:101.19,103.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:104.3,104.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:104.29,106.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:107.3,109.17 3 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:109.17,111.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:112.3,113.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:115.10,116.95 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:31.105,33.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:33.16,35.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:37.2,40.25 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:40.25,42.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:44.2,44.38 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:44.38,46.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:48.2,48.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:48.33,50.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:50.17,52.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:53.3,54.59 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:54.59,56.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:57.3,57.59 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:60.2,60.51 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:60.51,62.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:63.2,66.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:66.9,68.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:70.2,71.36 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:71.36,72.42 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:72.42,73.26 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:73.26,76.5 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:77.4,77.12 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:79.3,80.13 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:82.2,82.55 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:82.55,84.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:86.2,86.51 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:89.105,91.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:91.16,93.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:95.2,98.33 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:98.33,100.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:102.2,102.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:102.52,104.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:105.2,108.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:108.9,110.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:112.2,115.31 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:115.31,117.19 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:117.19,119.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:121.3,121.34 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:121.34,123.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:125.3,125.31 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:125.31,127.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:129.3,129.35 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:129.35,132.12 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:134.3,134.32 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:137.2,137.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:140.108,142.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:142.16,144.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:146.2,149.33 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:149.33,151.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:153.2,153.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:153.52,155.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:156.2,159.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:159.9,161.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:163.2,166.31 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:166.31,168.19 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:168.19,170.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:172.3,172.34 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:172.34,174.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:176.3,176.35 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:176.35,179.12 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:181.3,181.31 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:181.31,183.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:185.3,185.18 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:188.2,188.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:191.106,193.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:193.16,195.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:197.2,199.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:199.33,201.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:203.2,203.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:203.52,205.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:206.2,209.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:209.9,211.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:213.2,214.27 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:214.27,215.32 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:215.32,217.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:219.3,219.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:219.33,222.12 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:224.3,224.29 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:224.29,226.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:229.2,229.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:232.111,234.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:234.16,236.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:238.2,241.19 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:241.19,243.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:243.17,245.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:246.3,246.13 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:246.13,248.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:249.3,249.12 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:252.2,253.19 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:253.19,254.46 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:254.46,256.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:256.9,258.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:261.2,261.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:261.33,263.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:265.2,265.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:265.52,267.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:268.2,271.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:271.9,273.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:276.2,276.24 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:276.24,278.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:278.17,280.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:281.3,281.34 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:281.34,283.18 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:283.18,284.36 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:284.36,286.14 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:288.5,288.37 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:288.37,291.14 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:293.5,293.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:293.33,295.14 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:299.3,299.26 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:303.2,304.29 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:304.29,306.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:309.2,311.46 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:311.46,315.16 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:315.16,316.59 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:316.59,318.5 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:322.2,323.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:323.16,325.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:326.2,326.38 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:326.38,328.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:328.17,329.41 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:329.41,331.13 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:333.4,333.42 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:333.42,336.13 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:338.4,338.38 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:338.38,340.13 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:345.2,345.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:348.105,350.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:350.16,352.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:354.2,356.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:356.33,358.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:360.2,360.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:360.52,362.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:363.2,366.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:366.9,368.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:370.2,370.55 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:373.106,375.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:375.16,377.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:379.2,381.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:381.33,383.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:385.2,385.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:385.52,387.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:388.2,391.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:391.9,393.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:395.2,396.29 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:396.29,398.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:400.2,400.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:403.108,405.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:405.16,407.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:409.2,415.47 5 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:415.47,417.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:417.17,419.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:420.3,420.21 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:421.8,423.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:423.17,425.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:426.3,426.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:429.2,429.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:429.33,430.62 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:430.62,432.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:433.3,435.48 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:435.48,437.57 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:437.57,439.5 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:440.4,440.96 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:441.9,443.57 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:443.57,445.5 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:446.4,446.60 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:450.2,450.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:450.52,452.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:453.2,456.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:456.9,458.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:460.2,460.24 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:460.24,462.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:464.2,464.28 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:465.10,466.69 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:467.11,469.48 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:469.48,471.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:471.9,473.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:474.15,476.48 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:476.48,478.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:478.9,480.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:483.2,483.55 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:483.55,485.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:487.2,487.40 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:487.40,489.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:491.2,492.47 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:495.108,497.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:497.16,499.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:501.2,503.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:503.33,505.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:507.2,507.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:507.52,509.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:510.2,513.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:513.9,515.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:517.2,518.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:518.33,520.34 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:520.34,522.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:523.3,523.35 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:523.35,526.4 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:527.3,527.31 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:527.31,529.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:532.2,532.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:535.108,537.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:537.16,539.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:541.2,544.33 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:544.33,546.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:548.2,548.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:548.52,550.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:551.2,554.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:554.9,556.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:558.2,558.24 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:558.24,560.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:562.2,562.30 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:565.105,567.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:567.16,569.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:571.2,574.33 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:574.33,576.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:578.2,578.51 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:578.51,580.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:581.2,584.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:584.9,586.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:588.2,590.31 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:590.31,591.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:591.25,594.4 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:597.2,597.55 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:597.55,599.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:601.2,601.51 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:604.33,725.2 1 0 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:22.50,23.18 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:23.18,25.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:26.2,26.22 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:29.52,30.18 1 0 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:30.18,32.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:33.2,33.22 1 0 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:36.50,37.18 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:37.18,39.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:40.2,40.22 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:43.53,44.18 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:44.18,46.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:47.2,47.22 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:50.51,51.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:51.19,53.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:54.2,54.21 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:57.56,58.34 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:58.34,60.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:61.2,61.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:61.19,63.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:64.2,64.22 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:67.50,68.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:68.19,70.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:71.2,71.21 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:74.51,75.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:75.19,77.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:78.2,78.21 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:81.53,82.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:82.19,84.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:85.2,85.22 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:88.53,89.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:89.19,91.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:92.2,92.21 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:95.53,96.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:96.19,98.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:99.2,99.22 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:102.50,103.18 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:103.18,105.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:106.2,106.22 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:28.113,30.9 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:30.9,32.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:34.2,36.24 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:36.24,38.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:40.2,43.17 3 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:46.115,48.9 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:48.9,50.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:52.2,56.66 3 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:59.108,61.9 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:61.9,63.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:64.2,64.19 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:64.19,66.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:67.2,68.42 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:71.113,72.18 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:72.18,74.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:76.2,77.9 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:77.9,79.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:81.2,82.19 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:82.19,84.3 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:86.2,86.38 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:89.109,91.9 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:91.9,93.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:94.2,95.49 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:98.112,100.9 2 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:100.9,102.3 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:103.2,103.36 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:106.33,114.60 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:114.60,116.21 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:116.21,118.6 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:119.5,119.24 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:129.60,131.21 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:131.21,133.6 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:134.5,134.24 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:144.60,146.22 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:146.22,148.6 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:149.5,149.33 1 1 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:161.60,164.5 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:175.60,178.5 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:187.60,187.86 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:188.101,190.5 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:200.62,200.88 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:209.62,209.88 1 0 -github.com/echovault/echovault/pkg/modules/pubsub/commands.go:219.62,219.85 1 0 +github.com/echovault/echovault/pkg/modules/connection/commands.go:26.108,27.18 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:28.10,29.54 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:30.9,31.34 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:32.9,33.72 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:37.33,45.60 1 0 +github.com/echovault/echovault/pkg/modules/connection/commands.go:45.60,47.5 1 0 github.com/echovault/echovault/pkg/modules/list/commands.go:30.105,32.16 2 1 github.com/echovault/echovault/pkg/modules/list/commands.go:32.16,34.3 1 1 github.com/echovault/echovault/pkg/modules/list/commands.go:36.2,38.33 2 1 @@ -1884,12 +1333,6 @@ github.com/echovault/echovault/pkg/modules/list/key_funcs.go:82.2,82.30 1 1 github.com/echovault/echovault/pkg/modules/list/key_funcs.go:85.51,86.19 1 1 github.com/echovault/echovault/pkg/modules/list/key_funcs.go:86.19,88.3 1 1 github.com/echovault/echovault/pkg/modules/list/key_funcs.go:89.2,89.38 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:26.108,27.18 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:28.10,29.54 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:30.9,31.34 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:32.9,33.72 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:37.33,45.60 1 0 -github.com/echovault/echovault/pkg/modules/connection/commands.go:45.60,47.5 1 0 github.com/echovault/echovault/pkg/modules/admin/commands.go:29.115,35.29 4 1 github.com/echovault/echovault/pkg/modules/admin/commands.go:35.29,36.54 1 1 github.com/echovault/echovault/pkg/modules/admin/commands.go:36.54,42.42 4 1 @@ -1966,6 +1409,563 @@ github.com/echovault/echovault/pkg/modules/admin/commands.go:284.60,286.5 1 0 github.com/echovault/echovault/pkg/modules/admin/commands.go:287.113,288.47 1 0 github.com/echovault/echovault/pkg/modules/admin/commands.go:288.47,290.6 1 0 github.com/echovault/echovault/pkg/modules/admin/commands.go:291.5,291.45 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:36.104,38.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:38.16,40.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:42.2,48.16 6 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:48.16,50.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:54.2,54.16 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:54.16,55.34 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:55.34,57.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:57.9,59.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:62.2,62.44 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:62.44,64.34 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:64.34,66.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:67.3,67.36 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:68.8,68.51 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:68.51,70.33 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:70.33,72.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:73.3,73.45 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:74.8,76.34 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:76.34,79.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:79.9,82.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:84.2,84.16 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:84.16,86.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:87.2,89.76 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:89.76,91.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:94.2,94.28 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:94.28,96.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:98.2,98.17 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:101.105,102.44 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:102.44,104.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:106.2,109.15 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:109.15,110.29 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:110.29,111.16 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:111.16,117.5 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:122.2,122.30 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:122.30,123.15 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:123.15,128.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:133.2,133.28 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:133.28,134.31 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:134.31,135.52 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:135.52,137.5 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:138.4,139.12 2 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:141.3,141.60 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:141.60,143.4 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:144.3,144.55 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:148.2,148.28 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:148.28,149.58 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:149.58,151.4 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:154.2,154.42 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:157.104,159.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:159.16,161.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:162.2,164.33 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:164.33,166.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:168.2,169.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:169.16,171.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:172.2,176.51 3 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:179.105,181.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:181.16,183.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:185.2,188.27 3 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:188.27,189.31 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:189.31,191.12 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:193.3,193.33 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:193.33,195.18 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:195.18,197.5 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:198.4,199.12 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:201.3,201.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:203.2,203.15 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:203.15,204.34 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:204.34,205.14 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:205.14,208.5 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:212.2,212.28 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:212.28,214.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:216.2,218.30 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:218.30,219.24 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:219.24,221.12 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:223.3,223.96 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:226.2,226.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:229.104,231.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:231.16,233.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:234.2,235.27 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:235.27,237.17 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:237.17,239.12 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:241.3,241.13 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:243.2,243.51 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:246.108,248.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:248.16,250.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:252.2,254.33 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:254.33,256.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:258.2,258.51 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:258.51,260.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:261.2,264.31 3 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:264.31,266.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:268.2,270.30 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:273.111,275.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:275.16,277.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:279.2,281.33 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:281.33,283.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:285.2,285.52 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:285.52,287.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:288.2,292.31 3 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:292.31,294.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:296.2,297.46 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:297.46,299.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:301.2,301.47 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:304.104,306.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:306.16,308.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:310.2,314.33 3 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:314.33,316.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:318.2,318.52 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:318.52,320.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:321.2,325.31 3 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:325.31,327.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:329.2,330.39 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:330.39,332.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:334.2,334.12 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:334.12,336.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:338.2,338.47 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:341.107,343.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:343.16,345.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:347.2,351.16 3 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:351.16,353.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:354.2,355.42 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:355.42,357.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:359.2,359.33 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:359.33,361.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:363.2,363.51 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:363.51,365.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:366.2,368.19 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:368.19,371.3 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:373.2,375.33 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:376.12,377.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:377.39,379.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:380.3,380.46 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:381.12,382.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:382.39,384.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:385.3,385.46 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:386.12,387.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:387.39,389.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:390.3,390.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:390.39,392.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:393.3,393.46 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:394.12,395.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:395.39,396.40 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:396.40,398.5 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:399.4,399.47 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:401.3,401.46 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:402.10,403.71 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:406.2,406.30 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:409.109,411.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:411.16,413.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:415.2,419.16 3 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:419.16,421.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:422.2,423.44 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:423.44,425.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:427.2,427.33 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:427.33,429.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:431.2,431.51 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:431.51,433.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:434.2,436.19 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:436.19,439.3 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:441.2,443.33 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:444.12,445.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:445.39,447.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:448.3,448.46 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:449.12,450.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:450.39,452.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:453.3,453.46 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:454.12,455.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:455.39,457.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:458.3,458.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:458.39,460.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:461.3,461.46 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:462.12,463.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:463.39,464.40 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:464.40,466.5 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:467.4,467.47 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:469.3,469.46 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:470.10,471.71 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:474.2,474.30 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:477.33,646.2 1 0 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:22.49,23.34 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:23.34,25.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:26.2,26.30 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:29.50,30.25 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:30.25,32.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:33.2,34.30 2 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:34.30,35.15 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:35.15,37.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:39.2,39.18 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:42.49,43.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:43.19,45.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:46.2,46.30 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:49.50,50.18 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:50.18,52.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:53.2,53.21 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:56.49,57.18 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:57.18,59.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:60.2,60.21 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:63.53,64.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:64.19,66.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:67.2,67.21 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:70.56,71.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:71.19,73.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:74.2,74.21 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:77.49,78.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:78.19,80.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:81.2,81.21 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:84.52,85.34 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:85.34,87.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:88.2,88.30 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:91.54,92.34 1 0 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:92.34,94.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:95.2,95.30 1 0 +github.com/echovault/echovault/pkg/modules/generic/utils.go:32.96,33.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:33.19,35.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:36.2,36.33 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:37.13,39.53 2 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:41.12,42.26 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:42.26,44.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:45.3,46.53 2 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:48.12,49.26 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:49.26,51.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:52.3,53.53 2 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:55.12,56.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:56.19,58.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:59.3,59.29 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:59.29,61.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:62.3,64.17 3 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:64.17,66.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:67.3,68.53 2 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:70.12,71.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:71.19,73.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:74.3,74.29 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:74.29,76.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:77.3,79.17 3 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:79.17,81.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:82.3,83.53 2 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:85.14,86.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:86.19,88.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:89.3,89.29 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:89.29,91.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:92.3,94.17 3 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:94.17,96.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:97.3,98.53 2 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:100.14,101.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:101.19,103.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:104.3,104.29 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:104.29,106.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:107.3,109.17 3 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:109.17,111.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:112.3,113.53 2 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:115.10,116.95 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:31.105,33.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:33.16,35.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:37.2,40.25 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:40.25,42.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:44.2,44.38 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:44.38,46.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:48.2,48.33 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:48.33,50.17 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:50.17,52.4 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:53.3,54.59 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:54.59,56.4 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:57.3,57.59 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:60.2,60.51 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:60.51,62.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:63.2,66.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:66.9,68.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:70.2,71.36 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:71.36,72.42 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:72.42,73.26 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:73.26,76.5 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:77.4,77.12 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:79.3,80.13 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:82.2,82.55 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:82.55,84.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:86.2,86.51 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:89.105,91.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:91.16,93.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:95.2,98.33 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:98.33,100.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:102.2,102.52 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:102.52,104.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:105.2,108.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:108.9,110.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:112.2,115.31 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:115.31,117.19 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:117.19,119.12 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:121.3,121.34 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:121.34,123.12 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:125.3,125.31 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:125.31,127.12 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:129.3,129.35 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:129.35,132.12 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:134.3,134.32 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:137.2,137.25 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:140.108,142.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:142.16,144.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:146.2,149.33 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:149.33,151.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:153.2,153.52 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:153.52,155.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:156.2,159.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:159.9,161.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:163.2,166.31 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:166.31,168.19 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:168.19,170.12 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:172.3,172.34 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:172.34,174.12 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:176.3,176.35 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:176.35,179.12 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:181.3,181.31 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:181.31,183.12 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:185.3,185.18 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:188.2,188.25 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:191.106,193.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:193.16,195.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:197.2,199.33 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:199.33,201.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:203.2,203.52 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:203.52,205.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:206.2,209.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:209.9,211.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:213.2,214.27 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:214.27,215.32 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:215.32,217.12 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:219.3,219.33 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:219.33,222.12 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:224.3,224.29 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:224.29,226.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:229.2,229.25 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:232.111,234.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:234.16,236.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:238.2,241.19 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:241.19,243.17 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:243.17,245.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:246.3,246.13 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:246.13,248.4 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:249.3,249.12 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:252.2,253.19 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:253.19,254.46 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:254.46,256.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:256.9,258.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:261.2,261.33 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:261.33,263.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:265.2,265.52 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:265.52,267.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:268.2,271.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:271.9,273.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:276.2,276.24 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:276.24,278.17 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:278.17,280.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:281.3,281.34 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:281.34,283.18 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:283.18,284.36 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:284.36,286.14 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:288.5,288.37 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:288.37,291.14 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:293.5,293.33 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:293.33,295.14 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:299.3,299.26 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:303.2,304.29 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:304.29,306.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:309.2,311.46 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:311.46,315.16 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:315.16,316.59 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:316.59,318.5 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:322.2,323.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:323.16,325.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:326.2,326.38 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:326.38,328.17 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:328.17,329.41 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:329.41,331.13 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:333.4,333.42 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:333.42,336.13 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:338.4,338.38 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:338.38,340.13 2 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:345.2,345.25 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:348.105,350.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:350.16,352.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:354.2,356.33 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:356.33,358.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:360.2,360.52 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:360.52,362.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:363.2,366.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:366.9,368.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:370.2,370.55 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:373.106,375.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:375.16,377.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:379.2,381.33 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:381.33,383.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:385.2,385.52 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:385.52,387.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:388.2,391.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:391.9,393.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:395.2,396.29 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:396.29,398.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:400.2,400.25 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:403.108,405.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:405.16,407.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:409.2,415.47 5 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:415.47,417.17 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:417.17,419.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:420.3,420.21 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:421.8,423.17 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:423.17,425.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:426.3,426.19 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:429.2,429.33 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:429.33,430.62 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:430.62,432.4 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:433.3,435.48 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:435.48,437.57 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:437.57,439.5 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:440.4,440.96 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:441.9,443.57 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:443.57,445.5 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:446.4,446.60 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:450.2,450.52 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:450.52,452.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:453.2,456.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:456.9,458.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:460.2,460.24 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:460.24,462.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:464.2,464.28 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:465.10,466.69 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:467.11,469.48 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:469.48,471.4 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:471.9,473.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:474.15,476.48 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:476.48,478.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:478.9,480.4 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:483.2,483.55 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:483.55,485.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:487.2,487.40 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:487.40,489.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:491.2,492.47 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:495.108,497.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:497.16,499.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:501.2,503.33 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:503.33,505.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:507.2,507.52 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:507.52,509.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:510.2,513.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:513.9,515.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:517.2,518.33 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:518.33,520.34 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:520.34,522.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:523.3,523.35 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:523.35,526.4 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:527.3,527.31 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:527.31,529.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:532.2,532.25 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:535.108,537.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:537.16,539.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:541.2,544.33 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:544.33,546.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:548.2,548.52 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:548.52,550.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:551.2,554.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:554.9,556.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:558.2,558.24 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:558.24,560.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:562.2,562.30 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:565.105,567.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:567.16,569.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:571.2,574.33 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:574.33,576.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:578.2,578.51 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:578.51,580.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:581.2,584.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:584.9,586.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:588.2,590.31 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:590.31,591.25 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:591.25,594.4 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:597.2,597.55 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:597.55,599.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:601.2,601.51 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:604.33,725.2 1 0 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:22.50,23.18 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:23.18,25.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:26.2,26.22 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:29.52,30.18 1 0 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:30.18,32.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:33.2,33.22 1 0 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:36.50,37.18 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:37.18,39.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:40.2,40.22 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:43.53,44.18 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:44.18,46.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:47.2,47.22 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:50.51,51.19 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:51.19,53.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:54.2,54.21 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:57.56,58.34 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:58.34,60.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:61.2,61.19 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:61.19,63.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:64.2,64.22 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:67.50,68.19 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:68.19,70.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:71.2,71.21 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:74.51,75.19 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:75.19,77.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:78.2,78.21 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:81.53,82.19 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:82.19,84.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:85.2,85.22 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:88.53,89.19 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:89.19,91.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:92.2,92.21 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:95.53,96.19 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:96.19,98.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:99.2,99.22 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:102.50,103.18 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:103.18,105.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:106.2,106.22 1 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:28.113,30.9 2 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:30.9,32.3 1 0 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:34.2,36.24 2 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:36.24,38.3 1 0 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:40.2,43.17 3 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:46.115,48.9 2 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:48.9,50.3 1 0 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:52.2,56.66 3 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:59.108,61.9 2 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:61.9,63.3 1 0 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:64.2,64.19 1 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:64.19,66.3 1 0 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:67.2,68.42 2 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:71.113,72.18 1 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:72.18,74.3 1 0 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:76.2,77.9 2 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:77.9,79.3 1 0 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:81.2,82.19 2 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:82.19,84.3 1 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:86.2,86.38 1 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:89.109,91.9 2 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:91.9,93.3 1 0 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:94.2,95.49 2 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:98.112,100.9 2 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:100.9,102.3 1 0 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:103.2,103.36 1 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:106.33,114.60 1 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:114.60,116.21 1 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:116.21,118.6 1 0 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:119.5,119.24 1 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:129.60,131.21 1 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:131.21,133.6 1 0 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:134.5,134.24 1 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:144.60,146.22 1 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:146.22,148.6 1 0 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:149.5,149.33 1 1 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:161.60,164.5 1 0 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:175.60,178.5 1 0 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:187.60,187.86 1 0 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:188.101,190.5 1 0 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:200.62,200.88 1 0 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:209.62,209.88 1 0 +github.com/echovault/echovault/pkg/modules/pubsub/commands.go:219.62,219.85 1 0 github.com/echovault/echovault/pkg/modules/set/commands.go:30.108,32.16 2 1 github.com/echovault/echovault/pkg/modules/set/commands.go:32.16,34.3 1 1 github.com/echovault/echovault/pkg/modules/set/commands.go:36.2,40.33 3 1 diff --git a/pkg/modules/string/commands_test.go b/pkg/modules/string/commands_test.go index ee7ee2c7..1851c352 100644 --- a/pkg/modules/string/commands_test.go +++ b/pkg/modules/string/commands_test.go @@ -41,6 +41,7 @@ func init() { func Test_HandleSetRange(t *testing.T) { tests := []struct { + name string preset bool key string presetValue string @@ -49,7 +50,8 @@ func Test_HandleSetRange(t *testing.T) { expectedResponse int expectedError error }{ - { // Test that SETRANGE on non-existent string creates new string + { + name: "Test that SETRANGE on non-existent string creates new string", preset: false, key: "SetRangeKey1", presetValue: "", @@ -58,7 +60,8 @@ func Test_HandleSetRange(t *testing.T) { expectedResponse: len("New String Value"), expectedError: nil, }, - { // Test SETRANGE with an offset that leads to a longer resulting string + { + name: "Test SETRANGE with an offset that leads to a longer resulting string", preset: true, key: "SetRangeKey2", presetValue: "Original String Value", @@ -67,7 +70,8 @@ func Test_HandleSetRange(t *testing.T) { expectedResponse: len("Original String Portion Replaced With This New String"), expectedError: nil, }, - { // SETRANGE with negative offset prepends the string + { + name: "SETRANGE with negative offset prepends the string", preset: true, key: "SetRangeKey3", presetValue: "This is a preset value", @@ -76,7 +80,8 @@ func Test_HandleSetRange(t *testing.T) { expectedResponse: len("Prepended This is a preset value"), expectedError: nil, }, - { // SETRANGE with offset that embeds new string inside the old string + { + name: "SETRANGE with offset that embeds new string inside the old string", preset: true, key: "SetRangeKey4", presetValue: "This is a preset value", @@ -85,7 +90,8 @@ func Test_HandleSetRange(t *testing.T) { expectedResponse: len("That is a preset value"), expectedError: nil, }, - { // SETRANGE with offset longer than original lengths appends the string + { + name: "SETRANGE with offset longer than original lengths appends the string", preset: true, key: "SetRangeKey5", presetValue: "This is a preset value", @@ -94,7 +100,8 @@ func Test_HandleSetRange(t *testing.T) { expectedResponse: len("This is a preset value Appended"), expectedError: nil, }, - { // SETRANGE with offset on the last character replaces last character with new string + { + name: "SETRANGE with offset on the last character replaces last character with new string", preset: true, key: "SetRangeKey6", presetValue: "This is a preset value", @@ -103,13 +110,15 @@ func Test_HandleSetRange(t *testing.T) { expectedResponse: len("This is a preset valu replaced"), expectedError: nil, }, - { // Offset not integer + { + name: " Offset not integer", preset: false, command: []string{"SETRANGE", "key", "offset", "value"}, expectedResponse: 0, expectedError: errors.New("offset must be an integer"), }, - { // SETRANGE target is not a string + { + name: "SETRANGE target is not a string", preset: true, key: "test-int", presetValue: "10", @@ -117,13 +126,15 @@ func Test_HandleSetRange(t *testing.T) { expectedResponse: 0, expectedError: errors.New("value at key test-int is not a string"), }, - { // Command too short + { + name: "Command too short", preset: false, command: []string{"SETRANGE", "key"}, expectedResponse: 0, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Command too long + { + name: "Command too long", preset: false, command: []string{"SETRANGE", "key", "offset", "value", "value1"}, expectedResponse: 0, @@ -132,55 +143,58 @@ func Test_HandleSetRange(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SETRANGE, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SETRANGE, %d", i)) - // If there's a preset step, carry it out here - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + // If there's a preset step, carry it out here + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, internal.AdaptType(test.presetValue)); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + + res, err := handleSetRange(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + if err != nil { t.Error(err) } - if err := mockServer.SetValue(ctx, test.key, internal.AdaptType(test.presetValue)); err != nil { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - - res, err := handleSetRange(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response \"%d\", got \"%d\"", test.expectedResponse, rv.Integer()) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response \"%d\", got \"%d\"", test.expectedResponse, rv.Integer()) - } - // Get the value from the echovault and check against the expected value - if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { - t.Error(err) - } - value, ok := mockServer.GetValue(ctx, test.key).(string) - if !ok { - t.Error("expected string data type, got another type") - } - if value != test.expectedValue { - t.Errorf("expected value \"%s\", got \"%s\"", test.expectedValue, value) - } - mockServer.KeyRUnlock(ctx, test.key) + // Get the value from the echovault and check against the expected value + if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { + t.Error(err) + } + value, ok := mockServer.GetValue(ctx, test.key).(string) + if !ok { + t.Error("expected string data type, got another type") + } + if value != test.expectedValue { + t.Errorf("expected value \"%s\", got \"%s\"", test.expectedValue, value) + } + mockServer.KeyRUnlock(ctx, test.key) + }) } } func Test_HandleStrLen(t *testing.T) { tests := []struct { + name string preset bool key string presetValue string @@ -188,7 +202,8 @@ func Test_HandleStrLen(t *testing.T) { expectedResponse int expectedError error }{ - { // Return the correct string length for an existing string + { + name: "Return the correct string length for an existing string", preset: true, key: "StrLenKey1", presetValue: "Test String", @@ -196,7 +211,8 @@ func Test_HandleStrLen(t *testing.T) { expectedResponse: len("Test String"), expectedError: nil, }, - { // If the string does not exist, return 0 + { + name: "If the string does not exist, return 0", preset: false, key: "StrLenKey2", presetValue: "", @@ -204,7 +220,8 @@ func Test_HandleStrLen(t *testing.T) { expectedResponse: 0, expectedError: nil, }, - { // Too few args + { + name: "Too few args", preset: false, key: "StrLenKey3", presetValue: "", @@ -212,7 +229,8 @@ func Test_HandleStrLen(t *testing.T) { expectedResponse: 0, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Too many args + { + name: "Too many args", preset: false, key: "StrLenKey4", presetValue: "", @@ -223,38 +241,41 @@ func Test_HandleStrLen(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("STRLEN, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("STRLEN, %d", i)) - if test.preset { - _, err := mockServer.CreateKeyAndLock(ctx, test.key) - if err != nil { - t.Error(err) + if test.preset { + _, err := mockServer.CreateKeyAndLock(ctx, test.key) + if err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleStrLen(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleStrLen(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected respons \"%d\", got \"%d\"", test.expectedResponse, rv.Integer()) } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected respons \"%d\", got \"%d\"", test.expectedResponse, rv.Integer()) - } + }) } } func Test_HandleSubStr(t *testing.T) { tests := []struct { + name string preset bool key string presetValue string @@ -262,7 +283,8 @@ func Test_HandleSubStr(t *testing.T) { expectedResponse string expectedError error }{ - { // Return substring within the range of the string + { + name: "Return substring within the range of the string", preset: true, key: "SubStrKey1", presetValue: "Test String One", @@ -270,7 +292,8 @@ func Test_HandleSubStr(t *testing.T) { expectedResponse: "String", expectedError: nil, }, - { // Return substring at the end of the string with exact end index + { + name: "Return substring at the end of the string with exact end index", preset: true, key: "SubStrKey2", presetValue: "Test String Two", @@ -278,7 +301,8 @@ func Test_HandleSubStr(t *testing.T) { expectedResponse: "Two", expectedError: nil, }, - { // Return substring at the end of the string with end index greater than length + { + name: "Return substring at the end of the string with end index greater than length", preset: true, key: "SubStrKey3", presetValue: "Test String Three", @@ -286,7 +310,8 @@ func Test_HandleSubStr(t *testing.T) { expectedResponse: "Three", expectedError: nil, }, - { // Return the substring at the start of the string with 0 start index + { + name: "Return the substring at the start of the string with 0 start index", preset: true, key: "SubStrKey4", presetValue: "Test String Four", @@ -297,6 +322,7 @@ func Test_HandleSubStr(t *testing.T) { { // Return the substring with negative start index. // Substring should begin abs(start) from the end of the string when start is negative. + name: "Return the substring with negative start index", preset: true, key: "SubStrKey5", presetValue: "Test String Five", @@ -307,6 +333,7 @@ func Test_HandleSubStr(t *testing.T) { { // Return reverse substring with end index smaller than start index. // When end index is smaller than start index, the 2 indices are reversed. + name: "Return reverse substring with end index smaller than start index", preset: true, key: "SubStrKey6", presetValue: "Test String Six", @@ -314,55 +341,62 @@ func Test_HandleSubStr(t *testing.T) { expectedResponse: "tseT", expectedError: nil, }, - { // Command too short + { + name: "Command too short", command: []string{"SUBSTR", "key", "10"}, expectedError: errors.New(constants.WrongArgsResponse), }, { - // Command too long + name: "Command too long", command: []string{"SUBSTR", "key", "10", "15", "20"}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Start index is not an integer + { + name: "Start index is not an integer", command: []string{"SUBSTR", "key", "start", "10"}, expectedError: errors.New("start and end indices must be integers"), }, - { // End index is not an integer + { + name: "End index is not an integer", command: []string{"SUBSTR", "key", "0", "end"}, expectedError: errors.New("start and end indices must be integers"), }, - { // Non-existent key + { + name: "Non-existent key", command: []string{"SUBSTR", "non-existent-key", "0", "10"}, expectedError: errors.New("key non-existent-key does not exist"), }, } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SUBSTR, %d", i)) + t.Run(test.name, func(t *testing.T) { - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { - t.Error(err) + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SUBSTR, %d", i)) + + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + res, err := handleSubStr(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleSubStr(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if rv.String() != test.expectedResponse { + t.Errorf("expected response \"%s\", got \"%s\"", test.expectedResponse, rv.String()) } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.String() != test.expectedResponse { - t.Errorf("expected response \"%s\", got \"%s\"", test.expectedResponse, rv.String()) - } + }) } } From 7a77d4fd8139f6fb8552570fb54ad69acf155d45 Mon Sep 17 00:00:00 2001 From: Kelvin Mwinuka Date: Sat, 6 Apr 2024 00:24:04 +0800 Subject: [PATCH 4/8] Leverage t.Run for sorted_set module tests --- coverage/coverage.out | 1102 +++++------ pkg/modules/sorted_set/commands_test.go | 2251 +++++++++++++---------- 2 files changed, 1816 insertions(+), 1537 deletions(-) diff --git a/coverage/coverage.out b/coverage/coverage.out index 7920f91c..a293d55e 100644 --- a/coverage/coverage.out +++ b/coverage/coverage.out @@ -1108,557 +1108,6 @@ github.com/echovault/echovault/pkg/modules/acl/commands.go:578.62,580.7 1 1 github.com/echovault/echovault/pkg/modules/acl/commands.go:589.62,591.7 1 1 github.com/echovault/echovault/pkg/modules/acl/commands.go:603.62,605.7 1 0 github.com/echovault/echovault/pkg/modules/acl/commands.go:614.62,616.7 1 0 -github.com/echovault/echovault/pkg/modules/connection/commands.go:26.108,27.18 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:28.10,29.54 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:30.9,31.34 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:32.9,33.72 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:37.33,45.60 1 0 -github.com/echovault/echovault/pkg/modules/connection/commands.go:45.60,47.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:30.105,32.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:32.16,34.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:36.2,38.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:38.33,41.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:43.2,43.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:43.52,45.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:46.2,48.63 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:48.63,50.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:52.2,52.57 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:55.110,57.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:57.16,59.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:61.2,64.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:64.9,66.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:68.2,68.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:68.33,70.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:72.2,72.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:72.52,74.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:75.2,78.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:78.9,80.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:82.2,82.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:82.40,84.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:86.2,86.57 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:89.110,91.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:91.16,93.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:95.2,99.24 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:99.24,101.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:103.2,103.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:103.33,105.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:107.2,107.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:107.52,109.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:110.2,113.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:113.9,115.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:118.2,118.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:118.40,120.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:123.2,123.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:123.51,125.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:127.2,130.15 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:130.15,132.43 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:132.43,135.4 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:136.3,136.20 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:140.2,140.18 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:140.18,142.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:147.2,151.17 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:151.17,153.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:155.2,155.13 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:155.13,158.18 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:158.18,160.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:160.9,162.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:165.2,165.19 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:168.108,170.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:170.16,172.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:174.2,177.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:177.9,179.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:181.2,181.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:181.33,183.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:185.2,185.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:185.51,187.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:188.2,191.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:191.9,193.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:195.2,195.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:195.40,197.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:199.2,200.55 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:200.55,202.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:204.2,204.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:207.109,209.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:209.16,211.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:213.2,217.24 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:217.24,219.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:221.2,221.30 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:221.30,223.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:225.2,225.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:225.33,227.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:229.2,229.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:229.51,231.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:232.2,235.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:235.9,237.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:239.2,239.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:239.40,241.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:243.2,243.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:243.34,244.64 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:244.64,246.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:247.3,247.43 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:250.2,250.66 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:250.66,252.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:253.2,253.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:256.108,258.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:258.16,260.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:262.2,266.9 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:266.9,268.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:270.2,272.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:272.33,274.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:276.2,276.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:276.51,278.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:279.2,282.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:282.9,284.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:286.2,286.9 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:287.10,287.10 0 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:289.17,291.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:291.34,292.26 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:292.26,293.10 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:295.4,295.43 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:295.43,298.5 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:300.17,302.39 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:302.39,303.26 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:303.26,304.10 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:306.4,306.43 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:306.43,309.5 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:313.2,313.61 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:313.61,315.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:317.2,317.55 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:317.55,319.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:321.2,321.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:324.109,326.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:326.16,328.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:330.2,335.116 5 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:335.116,337.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:339.2,339.75 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:339.75,341.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:343.2,343.54 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:343.54,345.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:346.2,349.16 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:349.16,351.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:352.2,357.33 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:357.33,359.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:361.2,361.19 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:362.14,364.24 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:364.24,366.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:366.9,366.32 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:366.32,368.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:369.15,371.24 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:371.24,373.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:373.9,373.32 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:373.32,375.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:378.2,378.16 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:378.16,380.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:382.2,382.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:385.106,387.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:387.16,389.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:391.2,393.31 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:393.31,395.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:397.2,399.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:399.33,400.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:401.17,402.61 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:403.11,404.62 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:404.62,406.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:407.4,407.68 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:407.68,409.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:411.8,412.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:412.52,414.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:416.2,421.9 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:421.9,423.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:425.2,425.73 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:425.73,427.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:428.2,428.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:431.109,433.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:433.16,435.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:437.2,441.31 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:441.31,443.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:445.2,445.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:445.33,446.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:447.17,448.61 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:449.11,450.62 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:450.62,452.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:453.4,454.68 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:454.68,456.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:458.8,459.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:459.52,461.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:462.3,462.35 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:465.2,469.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:469.9,471.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:473.2,473.73 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:473.73,475.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:476.2,476.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:479.104,481.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:481.16,483.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:485.2,487.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:487.33,489.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:491.2,491.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:491.51,493.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:494.2,497.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:497.9,499.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:501.2,501.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:502.10,503.60 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:503.60,505.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:506.3,506.54 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:507.14,508.70 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:508.70,510.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:511.3,511.64 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:515.33,635.2 1 0 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:22.51,23.18 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:23.18,25.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:26.2,26.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:29.49,30.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:30.19,32.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:33.2,33.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:36.50,37.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:37.19,39.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:40.2,40.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:43.52,44.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:44.19,46.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:47.2,47.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:50.52,51.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:51.19,53.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:54.2,54.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:57.50,58.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:58.19,60.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:61.2,61.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:64.51,65.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:65.19,67.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:68.2,68.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:71.50,72.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:72.19,74.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:75.2,75.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:78.51,79.18 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:79.18,81.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:82.2,82.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:85.51,86.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:86.19,88.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:89.2,89.38 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:29.115,35.29 4 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:35.29,36.54 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:36.54,42.42 4 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:42.42,44.5 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:46.4,49.12 3 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:52.3,52.36 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:52.36,59.43 5 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:59.43,61.5 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:63.4,65.21 2 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:69.2,71.25 2 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:74.109,78.35 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:78.35,79.65 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:79.65,80.41 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:80.41,82.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:83.4,83.12 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:85.3,85.13 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:88.2,88.51 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:91.110,92.18 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:93.9,98.36 4 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:98.36,99.66 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:99.66,100.52 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:100.52,104.6 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:105.5,105.13 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:107.4,108.14 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:110.3,111.26 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:113.9,117.45 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:117.45,119.4 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:120.3,120.42 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:120.42,124.37 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:124.37,125.67 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:125.67,126.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:126.53,127.59 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:127.59,131.8 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:133.6,133.14 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:135.5,135.54 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:135.54,138.6 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:140.9,140.50 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:140.50,144.37 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:144.37,145.67 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:145.67,146.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:146.53,148.24 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:148.24,151.8 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:153.6,153.14 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:155.5,155.33 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:155.33,158.6 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:160.9,160.49 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:160.49,164.37 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:164.37,165.67 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:165.67,166.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:166.53,167.55 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:167.55,171.8 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:173.6,173.14 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:175.5,175.50 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:175.50,178.6 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:180.9,182.4 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:183.3,184.26 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:185.10,186.54 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:190.103,192.2 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:194.33,202.60 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:202.60,202.86 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:211.60,213.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:221.62,221.88 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:230.62,230.88 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:240.62,240.88 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:251.60,253.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:254.113,255.49 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:255.49,257.6 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:258.5,258.45 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:267.60,269.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:270.113,272.18 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:272.18,274.6 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:275.5,275.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:284.60,286.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:287.113,288.47 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:288.47,290.6 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:291.5,291.45 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:36.104,38.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:38.16,40.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:42.2,48.16 6 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:48.16,50.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:54.2,54.16 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:54.16,55.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:55.34,57.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:57.9,59.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:62.2,62.44 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:62.44,64.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:64.34,66.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:67.3,67.36 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:68.8,68.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:68.51,70.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:70.33,72.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:73.3,73.45 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:74.8,76.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:76.34,79.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:79.9,82.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:84.2,84.16 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:84.16,86.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:87.2,89.76 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:89.76,91.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:94.2,94.28 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:94.28,96.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:98.2,98.17 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:101.105,102.44 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:102.44,104.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:106.2,109.15 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:109.15,110.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:110.29,111.16 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:111.16,117.5 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:122.2,122.30 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:122.30,123.15 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:123.15,128.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:133.2,133.28 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:133.28,134.31 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:134.31,135.52 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:135.52,137.5 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:138.4,139.12 2 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:141.3,141.60 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:141.60,143.4 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:144.3,144.55 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:148.2,148.28 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:148.28,149.58 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:149.58,151.4 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:154.2,154.42 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:157.104,159.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:159.16,161.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:162.2,164.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:164.33,166.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:168.2,169.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:169.16,171.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:172.2,176.51 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:179.105,181.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:181.16,183.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:185.2,188.27 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:188.27,189.31 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:189.31,191.12 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:193.3,193.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:193.33,195.18 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:195.18,197.5 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:198.4,199.12 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:201.3,201.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:203.2,203.15 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:203.15,204.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:204.34,205.14 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:205.14,208.5 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:212.2,212.28 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:212.28,214.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:216.2,218.30 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:218.30,219.24 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:219.24,221.12 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:223.3,223.96 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:226.2,226.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:229.104,231.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:231.16,233.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:234.2,235.27 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:235.27,237.17 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:237.17,239.12 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:241.3,241.13 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:243.2,243.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:246.108,248.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:248.16,250.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:252.2,254.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:254.33,256.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:258.2,258.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:258.51,260.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:261.2,264.31 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:264.31,266.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:268.2,270.30 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:273.111,275.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:275.16,277.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:279.2,281.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:281.33,283.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:285.2,285.52 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:285.52,287.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:288.2,292.31 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:292.31,294.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:296.2,297.46 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:297.46,299.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:301.2,301.47 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:304.104,306.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:306.16,308.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:310.2,314.33 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:314.33,316.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:318.2,318.52 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:318.52,320.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:321.2,325.31 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:325.31,327.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:329.2,330.39 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:330.39,332.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:334.2,334.12 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:334.12,336.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:338.2,338.47 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:341.107,343.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:343.16,345.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:347.2,351.16 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:351.16,353.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:354.2,355.42 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:355.42,357.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:359.2,359.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:359.33,361.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:363.2,363.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:363.51,365.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:366.2,368.19 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:368.19,371.3 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:373.2,375.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:376.12,377.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:377.39,379.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:380.3,380.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:381.12,382.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:382.39,384.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:385.3,385.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:386.12,387.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:387.39,389.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:390.3,390.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:390.39,392.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:393.3,393.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:394.12,395.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:395.39,396.40 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:396.40,398.5 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:399.4,399.47 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:401.3,401.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:402.10,403.71 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:406.2,406.30 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:409.109,411.16 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:411.16,413.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:415.2,419.16 3 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:419.16,421.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:422.2,423.44 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:423.44,425.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:427.2,427.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:427.33,429.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:431.2,431.51 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:431.51,433.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/commands.go:434.2,436.19 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:436.19,439.3 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:441.2,443.33 2 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:444.12,445.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:445.39,447.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:448.3,448.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:449.12,450.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:450.39,452.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:453.3,453.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:454.12,455.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:455.39,457.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:458.3,458.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:458.39,460.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:461.3,461.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:462.12,463.39 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:463.39,464.40 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:464.40,466.5 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:467.4,467.47 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:469.3,469.46 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:470.10,471.71 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:474.2,474.30 1 1 -github.com/echovault/echovault/pkg/modules/generic/commands.go:477.33,646.2 1 0 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:22.49,23.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:23.34,25.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:26.2,26.30 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:29.50,30.25 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:30.25,32.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:33.2,34.30 2 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:34.30,35.15 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:35.15,37.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:39.2,39.18 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:42.49,43.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:43.19,45.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:46.2,46.30 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:49.50,50.18 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:50.18,52.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:53.2,53.21 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:56.49,57.18 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:57.18,59.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:60.2,60.21 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:63.53,64.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:64.19,66.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:67.2,67.21 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:70.56,71.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:71.19,73.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:74.2,74.21 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:77.49,78.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:78.19,80.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:81.2,81.21 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:84.52,85.34 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:85.34,87.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:88.2,88.30 1 1 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:91.54,92.34 1 0 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:92.34,94.3 1 0 -github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:95.2,95.30 1 0 -github.com/echovault/echovault/pkg/modules/generic/utils.go:32.96,33.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:33.19,35.3 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:36.2,36.33 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:37.13,39.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:41.12,42.26 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:42.26,44.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:45.3,46.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:48.12,49.26 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:49.26,51.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:52.3,53.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:55.12,56.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:56.19,58.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:59.3,59.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:59.29,61.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:62.3,64.17 3 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:64.17,66.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:67.3,68.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:70.12,71.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:71.19,73.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:74.3,74.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:74.29,76.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:77.3,79.17 3 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:79.17,81.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:82.3,83.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:85.14,86.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:86.19,88.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:89.3,89.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:89.29,91.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:92.3,94.17 3 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:94.17,96.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:97.3,98.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:100.14,101.19 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:101.19,103.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:104.3,104.29 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:104.29,106.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:107.3,109.17 3 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:109.17,111.4 1 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:112.3,113.53 2 1 -github.com/echovault/echovault/pkg/modules/generic/utils.go:115.10,116.95 1 1 github.com/echovault/echovault/pkg/modules/hash/commands.go:31.105,33.16 2 1 github.com/echovault/echovault/pkg/modules/hash/commands.go:33.16,35.3 1 1 github.com/echovault/echovault/pkg/modules/hash/commands.go:37.2,40.25 3 1 @@ -1923,6 +1372,557 @@ github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:99.2,99.22 1 1 github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:102.50,103.18 1 1 github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:103.18,105.3 1 1 github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:106.2,106.22 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:36.104,38.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:38.16,40.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:42.2,48.16 6 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:48.16,50.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:54.2,54.16 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:54.16,55.34 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:55.34,57.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:57.9,59.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:62.2,62.44 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:62.44,64.34 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:64.34,66.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:67.3,67.36 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:68.8,68.51 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:68.51,70.33 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:70.33,72.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:73.3,73.45 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:74.8,76.34 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:76.34,79.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:79.9,82.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:84.2,84.16 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:84.16,86.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:87.2,89.76 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:89.76,91.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:94.2,94.28 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:94.28,96.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:98.2,98.17 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:101.105,102.44 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:102.44,104.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:106.2,109.15 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:109.15,110.29 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:110.29,111.16 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:111.16,117.5 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:122.2,122.30 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:122.30,123.15 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:123.15,128.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:133.2,133.28 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:133.28,134.31 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:134.31,135.52 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:135.52,137.5 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:138.4,139.12 2 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:141.3,141.60 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:141.60,143.4 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:144.3,144.55 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:148.2,148.28 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:148.28,149.58 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:149.58,151.4 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:154.2,154.42 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:157.104,159.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:159.16,161.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:162.2,164.33 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:164.33,166.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:168.2,169.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:169.16,171.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:172.2,176.51 3 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:179.105,181.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:181.16,183.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:185.2,188.27 3 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:188.27,189.31 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:189.31,191.12 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:193.3,193.33 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:193.33,195.18 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:195.18,197.5 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:198.4,199.12 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:201.3,201.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:203.2,203.15 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:203.15,204.34 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:204.34,205.14 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:205.14,208.5 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:212.2,212.28 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:212.28,214.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:216.2,218.30 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:218.30,219.24 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:219.24,221.12 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:223.3,223.96 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:226.2,226.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:229.104,231.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:231.16,233.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:234.2,235.27 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:235.27,237.17 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:237.17,239.12 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:241.3,241.13 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:243.2,243.51 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:246.108,248.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:248.16,250.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:252.2,254.33 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:254.33,256.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:258.2,258.51 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:258.51,260.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:261.2,264.31 3 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:264.31,266.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:268.2,270.30 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:273.111,275.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:275.16,277.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:279.2,281.33 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:281.33,283.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:285.2,285.52 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:285.52,287.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:288.2,292.31 3 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:292.31,294.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:296.2,297.46 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:297.46,299.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:301.2,301.47 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:304.104,306.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:306.16,308.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:310.2,314.33 3 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:314.33,316.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:318.2,318.52 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:318.52,320.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:321.2,325.31 3 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:325.31,327.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:329.2,330.39 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:330.39,332.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:334.2,334.12 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:334.12,336.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:338.2,338.47 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:341.107,343.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:343.16,345.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:347.2,351.16 3 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:351.16,353.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:354.2,355.42 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:355.42,357.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:359.2,359.33 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:359.33,361.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:363.2,363.51 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:363.51,365.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:366.2,368.19 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:368.19,371.3 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:373.2,375.33 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:376.12,377.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:377.39,379.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:380.3,380.46 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:381.12,382.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:382.39,384.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:385.3,385.46 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:386.12,387.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:387.39,389.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:390.3,390.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:390.39,392.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:393.3,393.46 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:394.12,395.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:395.39,396.40 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:396.40,398.5 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:399.4,399.47 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:401.3,401.46 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:402.10,403.71 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:406.2,406.30 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:409.109,411.16 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:411.16,413.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:415.2,419.16 3 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:419.16,421.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:422.2,423.44 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:423.44,425.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:427.2,427.33 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:427.33,429.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:431.2,431.51 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:431.51,433.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/commands.go:434.2,436.19 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:436.19,439.3 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:441.2,443.33 2 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:444.12,445.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:445.39,447.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:448.3,448.46 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:449.12,450.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:450.39,452.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:453.3,453.46 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:454.12,455.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:455.39,457.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:458.3,458.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:458.39,460.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:461.3,461.46 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:462.12,463.39 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:463.39,464.40 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:464.40,466.5 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:467.4,467.47 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:469.3,469.46 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:470.10,471.71 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:474.2,474.30 1 1 +github.com/echovault/echovault/pkg/modules/generic/commands.go:477.33,646.2 1 0 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:22.49,23.34 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:23.34,25.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:26.2,26.30 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:29.50,30.25 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:30.25,32.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:33.2,34.30 2 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:34.30,35.15 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:35.15,37.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:39.2,39.18 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:42.49,43.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:43.19,45.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:46.2,46.30 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:49.50,50.18 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:50.18,52.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:53.2,53.21 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:56.49,57.18 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:57.18,59.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:60.2,60.21 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:63.53,64.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:64.19,66.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:67.2,67.21 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:70.56,71.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:71.19,73.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:74.2,74.21 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:77.49,78.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:78.19,80.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:81.2,81.21 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:84.52,85.34 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:85.34,87.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:88.2,88.30 1 1 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:91.54,92.34 1 0 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:92.34,94.3 1 0 +github.com/echovault/echovault/pkg/modules/generic/key_funcs.go:95.2,95.30 1 0 +github.com/echovault/echovault/pkg/modules/generic/utils.go:32.96,33.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:33.19,35.3 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:36.2,36.33 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:37.13,39.53 2 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:41.12,42.26 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:42.26,44.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:45.3,46.53 2 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:48.12,49.26 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:49.26,51.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:52.3,53.53 2 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:55.12,56.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:56.19,58.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:59.3,59.29 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:59.29,61.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:62.3,64.17 3 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:64.17,66.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:67.3,68.53 2 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:70.12,71.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:71.19,73.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:74.3,74.29 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:74.29,76.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:77.3,79.17 3 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:79.17,81.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:82.3,83.53 2 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:85.14,86.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:86.19,88.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:89.3,89.29 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:89.29,91.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:92.3,94.17 3 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:94.17,96.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:97.3,98.53 2 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:100.14,101.19 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:101.19,103.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:104.3,104.29 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:104.29,106.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:107.3,109.17 3 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:109.17,111.4 1 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:112.3,113.53 2 1 +github.com/echovault/echovault/pkg/modules/generic/utils.go:115.10,116.95 1 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:29.115,35.29 4 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:35.29,36.54 1 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:36.54,42.42 4 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:42.42,44.5 1 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:46.4,49.12 3 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:52.3,52.36 1 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:52.36,59.43 5 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:59.43,61.5 1 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:63.4,65.21 2 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:69.2,71.25 2 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:74.109,78.35 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:78.35,79.65 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:79.65,80.41 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:80.41,82.5 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:83.4,83.12 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:85.3,85.13 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:88.2,88.51 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:91.110,92.18 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:93.9,98.36 4 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:98.36,99.66 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:99.66,100.52 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:100.52,104.6 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:105.5,105.13 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:107.4,108.14 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:110.3,111.26 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:113.9,117.45 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:117.45,119.4 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:120.3,120.42 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:120.42,124.37 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:124.37,125.67 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:125.67,126.53 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:126.53,127.59 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:127.59,131.8 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:133.6,133.14 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:135.5,135.54 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:135.54,138.6 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:140.9,140.50 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:140.50,144.37 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:144.37,145.67 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:145.67,146.53 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:146.53,148.24 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:148.24,151.8 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:153.6,153.14 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:155.5,155.33 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:155.33,158.6 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:160.9,160.49 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:160.49,164.37 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:164.37,165.67 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:165.67,166.53 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:166.53,167.55 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:167.55,171.8 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:173.6,173.14 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:175.5,175.50 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:175.50,178.6 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:180.9,182.4 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:183.3,184.26 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:185.10,186.54 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:190.103,192.2 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:194.33,202.60 1 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:202.60,202.86 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:211.60,213.5 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:221.62,221.88 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:230.62,230.88 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:240.62,240.88 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:251.60,253.5 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:254.113,255.49 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:255.49,257.6 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:258.5,258.45 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:267.60,269.5 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:270.113,272.18 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:272.18,274.6 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:275.5,275.53 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:284.60,286.5 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:287.113,288.47 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:288.47,290.6 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:291.5,291.45 1 0 +github.com/echovault/echovault/pkg/modules/connection/commands.go:26.108,27.18 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:28.10,29.54 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:30.9,31.34 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:32.9,33.72 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:37.33,45.60 1 0 +github.com/echovault/echovault/pkg/modules/connection/commands.go:45.60,47.5 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:30.105,32.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:32.16,34.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:36.2,38.33 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:38.33,41.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:43.2,43.52 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:43.52,45.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:46.2,48.63 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:48.63,50.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:52.2,52.57 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:55.110,57.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:57.16,59.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:61.2,64.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:64.9,66.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:68.2,68.33 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:68.33,70.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:72.2,72.52 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:72.52,74.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:75.2,78.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:78.9,80.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:82.2,82.40 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:82.40,84.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:86.2,86.57 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:89.110,91.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:91.16,93.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:95.2,99.24 4 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:99.24,101.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:103.2,103.33 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:103.33,105.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:107.2,107.52 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:107.52,109.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:110.2,113.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:113.9,115.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:118.2,118.40 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:118.40,120.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:123.2,123.51 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:123.51,125.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:127.2,130.15 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:130.15,132.43 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:132.43,135.4 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:136.3,136.20 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:140.2,140.18 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:140.18,142.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:147.2,151.17 4 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:151.17,153.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:155.2,155.13 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:155.13,158.18 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:158.18,160.4 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:160.9,162.4 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:165.2,165.19 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:168.108,170.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:170.16,172.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:174.2,177.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:177.9,179.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:181.2,181.33 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:181.33,183.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:185.2,185.51 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:185.51,187.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:188.2,191.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:191.9,193.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:195.2,195.40 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:195.40,197.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:199.2,200.55 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:200.55,202.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:204.2,204.42 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:207.109,209.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:209.16,211.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:213.2,217.24 4 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:217.24,219.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:221.2,221.30 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:221.30,223.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:225.2,225.33 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:225.33,227.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:229.2,229.51 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:229.51,231.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:232.2,235.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:235.9,237.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:239.2,239.40 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:239.40,241.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:243.2,243.34 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:243.34,244.64 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:244.64,246.4 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:247.3,247.43 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:250.2,250.66 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:250.66,252.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:253.2,253.42 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:256.108,258.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:258.16,260.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:262.2,266.9 4 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:266.9,268.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:270.2,272.33 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:272.33,274.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:276.2,276.51 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:276.51,278.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:279.2,282.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:282.9,284.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:286.2,286.9 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:287.10,287.10 0 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:289.17,291.34 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:291.34,292.26 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:292.26,293.10 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:295.4,295.43 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:295.43,298.5 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:300.17,302.39 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:302.39,303.26 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:303.26,304.10 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:306.4,306.43 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:306.43,309.5 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:313.2,313.61 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:313.61,315.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:317.2,317.55 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:317.55,319.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:321.2,321.42 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:324.109,326.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:326.16,328.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:330.2,335.116 5 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:335.116,337.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:339.2,339.75 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:339.75,341.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:343.2,343.54 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:343.54,345.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:346.2,349.16 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:349.16,351.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:352.2,357.33 4 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:357.33,359.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:361.2,361.19 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:362.14,364.24 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:364.24,366.4 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:366.9,366.32 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:366.32,368.4 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:369.15,371.24 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:371.24,373.4 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:373.9,373.32 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:373.32,375.4 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:378.2,378.16 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:378.16,380.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:382.2,382.42 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:385.106,387.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:387.16,389.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:391.2,393.31 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:393.31,395.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:397.2,399.33 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:399.33,400.34 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:401.17,402.61 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:403.11,404.62 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:404.62,406.5 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:407.4,407.68 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:407.68,409.5 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:411.8,412.52 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:412.52,414.4 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:416.2,421.9 4 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:421.9,423.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:425.2,425.73 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:425.73,427.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:428.2,428.42 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:431.109,433.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:433.16,435.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:437.2,441.31 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:441.31,443.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:445.2,445.33 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:445.33,446.34 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:447.17,448.61 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:449.11,450.62 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:450.62,452.5 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:453.4,454.68 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:454.68,456.5 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:458.8,459.52 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:459.52,461.4 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:462.3,462.35 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:465.2,469.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:469.9,471.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:473.2,473.73 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:473.73,475.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:476.2,476.42 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:479.104,481.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:481.16,483.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:485.2,487.33 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:487.33,489.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:491.2,491.51 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:491.51,493.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:494.2,497.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:497.9,499.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:501.2,501.33 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:502.10,503.60 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:503.60,505.4 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:506.3,506.54 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:507.14,508.70 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:508.70,510.4 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:511.3,511.64 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:515.33,635.2 1 0 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:22.51,23.18 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:23.18,25.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:26.2,26.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:29.49,30.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:30.19,32.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:33.2,33.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:36.50,37.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:37.19,39.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:40.2,40.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:43.52,44.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:44.19,46.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:47.2,47.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:50.52,51.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:51.19,53.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:54.2,54.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:57.50,58.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:58.19,60.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:61.2,61.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:64.51,65.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:65.19,67.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:68.2,68.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:71.50,72.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:72.19,74.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:75.2,75.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:78.51,79.18 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:79.18,81.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:82.2,82.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:85.51,86.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:86.19,88.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:89.2,89.38 1 1 github.com/echovault/echovault/pkg/modules/pubsub/commands.go:28.113,30.9 2 1 github.com/echovault/echovault/pkg/modules/pubsub/commands.go:30.9,32.3 1 0 github.com/echovault/echovault/pkg/modules/pubsub/commands.go:34.2,36.24 2 1 diff --git a/pkg/modules/sorted_set/commands_test.go b/pkg/modules/sorted_set/commands_test.go index b37681b7..bf8ed36c 100644 --- a/pkg/modules/sorted_set/commands_test.go +++ b/pkg/modules/sorted_set/commands_test.go @@ -43,6 +43,7 @@ func init() { func Test_HandleZADD(t *testing.T) { tests := []struct { + name string preset bool presetValue *sorted_set.SortedSet key string @@ -51,7 +52,8 @@ func Test_HandleZADD(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Create new sorted set and return the cardinality of the new sorted set. + { + name: "1. Create new sorted set and return the cardinality of the new sorted set", preset: false, presetValue: nil, key: "ZaddKey1", @@ -66,7 +68,8 @@ func Test_HandleZADD(t *testing.T) { expectedResponse: 5, expectedError: nil, }, - { // 2. Only add the elements that do not currently exist in the sorted set when NX flag is provided + { + name: "2. Only add the elements that do not currently exist in the sorted set when NX flag is provided", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "member1", Score: sorted_set.Score(5.5)}, @@ -85,7 +88,8 @@ func Test_HandleZADD(t *testing.T) { expectedResponse: 2, expectedError: nil, }, - { // 3. Do not add any elements when providing existing members with NX flag + { + name: "Do not add any elements when providing existing members with NX flag", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "member1", Score: sorted_set.Score(5.5)}, @@ -102,7 +106,8 @@ func Test_HandleZADD(t *testing.T) { expectedResponse: 0, expectedError: nil, }, - { // 4. Successfully add elements to an existing set when XX flag is provided with existing elements + { + name: "Successfully add elements to an existing set when XX flag is provided with existing elements", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "member1", Score: sorted_set.Score(5.5)}, @@ -119,7 +124,8 @@ func Test_HandleZADD(t *testing.T) { expectedResponse: 3, expectedError: nil, }, - { // 5. Fail to add element when providing XX flag with elements that do not exist in the sorted set. + { + name: "5. Fail to add element when providing XX flag with elements that do not exist in the sorted set.", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "member1", Score: sorted_set.Score(5.5)}, @@ -137,8 +143,9 @@ func Test_HandleZADD(t *testing.T) { expectedError: nil, }, { - // 6. Only update the elements where provided score is greater than current score if GT flag + // 6. Only update the elements where provided score is greater than current score and GT flag is provided // Return only the new elements added by default + name: "6. Only update the elements where provided score is greater than current score and GT flag is provided", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "member1", Score: sorted_set.Score(5.5)}, @@ -158,6 +165,7 @@ func Test_HandleZADD(t *testing.T) { { // 7. Only update the elements where provided score is less than current score if LT flag is provided // Return only the new elements added by default. + name: "7. Only update the elements where provided score is less than current score if LT flag is provided", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "member1", Score: sorted_set.Score(5.5)}, @@ -175,7 +183,7 @@ func Test_HandleZADD(t *testing.T) { expectedError: nil, }, { - // 8. Return all the elements that were updated AND added when CH flag is provided + name: "8. Return all the elements that were updated AND added when CH flag is provided", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "member1", Score: sorted_set.Score(5.5)}, @@ -193,7 +201,7 @@ func Test_HandleZADD(t *testing.T) { expectedError: nil, }, { - // 9. Increment the member by score + name: "9. Increment the member by score", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "member1", Score: sorted_set.Score(5.5)}, @@ -210,7 +218,8 @@ func Test_HandleZADD(t *testing.T) { expectedResponse: 0, expectedError: nil, }, - { // 10. Fail when GT/LT flag is provided alongside NX flag + { + name: "10. Fail when GT/LT flag is provided alongside NX flag", preset: false, presetValue: nil, key: "ZaddKey10", @@ -219,7 +228,8 @@ func Test_HandleZADD(t *testing.T) { expectedResponse: 0, expectedError: errors.New("GT/LT flags not allowed if NX flag is provided"), }, - { // 11. Command is too short + { + name: "11. Command is too short", preset: false, presetValue: nil, key: "ZaddKey11", @@ -228,7 +238,8 @@ func Test_HandleZADD(t *testing.T) { expectedResponse: 0, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 12. Throw error when score/member entries are do not match + { + name: "12. Throw error when score/member entries are do not match", preset: false, presetValue: nil, key: "ZaddKey11", @@ -237,7 +248,8 @@ func Test_HandleZADD(t *testing.T) { expectedResponse: 0, expectedError: errors.New("score/member pairs must be float/string"), }, - { // 13. Throw error when INCR flag is passed with more than one score/member pair + { + name: "13. Throw error when INCR flag is passed with more than one score/member pair", preset: false, presetValue: nil, key: "ZaddKey13", @@ -249,55 +261,58 @@ func Test_HandleZADD(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZADD, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZADD, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleZADD(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + if err != nil { t.Error(err) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + rd := resp.NewReader(bytes.NewReader(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleZADD(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response %d at key \"%s\", got %d", test.expectedResponse, test.key, rv.Integer()) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewReader(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response %d at key \"%s\", got %d", test.expectedResponse, test.key, rv.Integer()) - } - // Fetch the sorted set from the echovault and check it against the expected result - if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { - t.Error(err) - } - sortedSet, ok := mockServer.GetValue(ctx, test.key).(*sorted_set.SortedSet) - if !ok { - t.Errorf("expected the value at key \"%s\" to be a sorted set, got another type", test.key) - } - if test.expectedValue == nil { - continue - } - if !sortedSet.Equals(test.expectedValue) { - t.Errorf("expected sorted set %+v, got %+v", test.expectedValue, sortedSet) - } - mockServer.KeyRUnlock(ctx, test.key) + // Fetch the sorted set from the echovault and check it against the expected result + if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { + t.Error(err) + } + sortedSet, ok := mockServer.GetValue(ctx, test.key).(*sorted_set.SortedSet) + if !ok { + t.Errorf("expected the value at key \"%s\" to be a sorted set, got another type", test.key) + } + if test.expectedValue == nil { + return + } + if !sortedSet.Equals(test.expectedValue) { + t.Errorf("expected sorted set %+v, got %+v", test.expectedValue, sortedSet) + } + mockServer.KeyRUnlock(ctx, test.key) + }) } } func Test_HandleZCARD(t *testing.T) { tests := []struct { + name string preset bool presetValue interface{} key string @@ -306,7 +321,8 @@ func Test_HandleZCARD(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Get cardinality of valid sorted set. + { + name: "1. Get cardinality of valid sorted set.", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "member1", Score: sorted_set.Score(5.5)}, @@ -319,7 +335,8 @@ func Test_HandleZCARD(t *testing.T) { expectedResponse: 3, expectedError: nil, }, - { // 2. Return 0 when trying to get cardinality from non-existent key + { + name: "2. Return 0 when trying to get cardinality from non-existent key", preset: false, presetValue: nil, key: "ZcardKey2", @@ -328,7 +345,8 @@ func Test_HandleZCARD(t *testing.T) { expectedResponse: 0, expectedError: nil, }, - { // 3. Command is too short + { + name: "3. Command is too short", preset: false, presetValue: nil, key: "ZcardKey3", @@ -337,7 +355,8 @@ func Test_HandleZCARD(t *testing.T) { expectedResponse: 0, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 4. Command too long + { // + name: "4. Command too long", preset: false, presetValue: nil, key: "ZcardKey4", @@ -346,7 +365,8 @@ func Test_HandleZCARD(t *testing.T) { expectedResponse: 0, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 5. Return error when not a sorted set + { + name: "5. Return error when not a sorted set", preset: true, presetValue: "Default value", key: "ZcardKey5", @@ -358,40 +378,43 @@ func Test_HandleZCARD(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZCARD, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZCARD, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleZCARD(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + if err != nil { t.Error(err) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + rd := resp.NewReader(bytes.NewReader(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleZCARD(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response %d at key \"%s\", got %d", test.expectedResponse, test.key, rv.Integer()) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewReader(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response %d at key \"%s\", got %d", test.expectedResponse, test.key, rv.Integer()) - } + }) } } func Test_HandleZCOUNT(t *testing.T) { tests := []struct { + name string preset bool presetValue interface{} key string @@ -400,7 +423,8 @@ func Test_HandleZCOUNT(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Get entire count using infinity boundaries + { + name: "1. Get entire count using infinity boundaries", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "member1", Score: sorted_set.Score(5.5)}, @@ -417,7 +441,8 @@ func Test_HandleZCOUNT(t *testing.T) { expectedResponse: 7, expectedError: nil, }, - { // 2. Get count of sub-set from -inf to limit + { + name: "2. Get count of sub-set from -inf to limit", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "member1", Score: sorted_set.Score(5.5)}, @@ -434,7 +459,8 @@ func Test_HandleZCOUNT(t *testing.T) { expectedResponse: 5, expectedError: nil, }, - { // 3. Get count of sub-set from bottom boundary to +inf limit + { + name: "3. Get count of sub-set from bottom boundary to +inf limit", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "member1", Score: sorted_set.Score(5.5)}, @@ -451,7 +477,8 @@ func Test_HandleZCOUNT(t *testing.T) { expectedResponse: 2, expectedError: nil, }, - { // 4. Return error when bottom boundary is not a valid double/float + { + name: "4. Return error when bottom boundary is not a valid double/float", preset: false, presetValue: nil, key: "ZcountKey4", @@ -460,7 +487,8 @@ func Test_HandleZCOUNT(t *testing.T) { expectedResponse: 0, expectedError: errors.New("min constraint must be a double"), }, - { // 5. Return error when top boundary is not a valid double/float + { + name: "5. Return error when top boundary is not a valid double/float", preset: false, presetValue: nil, key: "ZcountKey5", @@ -469,7 +497,8 @@ func Test_HandleZCOUNT(t *testing.T) { expectedResponse: 0, expectedError: errors.New("max constraint must be a double"), }, - { // 6. Command is too short + { + name: "6. Command is too short", preset: false, presetValue: nil, key: "ZcountKey6", @@ -478,7 +507,8 @@ func Test_HandleZCOUNT(t *testing.T) { expectedResponse: 0, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 7. Command too long + { + name: "7. Command too long", preset: false, presetValue: nil, key: "ZcountKey7", @@ -487,7 +517,8 @@ func Test_HandleZCOUNT(t *testing.T) { expectedResponse: 0, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 8. Throw error when value at the key is not a sorted set + { + name: "8. Throw error when value at the key is not a sorted set", preset: true, presetValue: "Default value", key: "ZcountKey8", @@ -499,40 +530,43 @@ func Test_HandleZCOUNT(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZCARD, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZCARD, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleZCOUNT(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + if err != nil { t.Error(err) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + rd := resp.NewReader(bytes.NewReader(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleZCOUNT(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response %d at key \"%s\", got %d", test.expectedResponse, test.key, rv.Integer()) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewReader(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response %d at key \"%s\", got %d", test.expectedResponse, test.key, rv.Integer()) - } + }) } } func Test_HandleZLEXCOUNT(t *testing.T) { tests := []struct { + name string preset bool presetValue interface{} key string @@ -541,7 +575,8 @@ func Test_HandleZLEXCOUNT(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Get entire count using infinity boundaries + { + name: "1. Get entire count using infinity boundaries", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "e", Score: sorted_set.Score(1)}, @@ -558,7 +593,8 @@ func Test_HandleZLEXCOUNT(t *testing.T) { expectedResponse: 5, expectedError: nil, }, - { // 2. Return 0 when the members do not have the same score + { + name: "2. Return 0 when the members do not have the same score", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "a", Score: sorted_set.Score(5.5)}, @@ -575,7 +611,8 @@ func Test_HandleZLEXCOUNT(t *testing.T) { expectedResponse: 0, expectedError: nil, }, - { // 3. Return 0 when the key does not exist + { + name: "3. Return 0 when the key does not exist", preset: false, presetValue: nil, key: "ZlexCountKey3", @@ -584,7 +621,8 @@ func Test_HandleZLEXCOUNT(t *testing.T) { expectedResponse: 0, expectedError: nil, }, - { // 4. Return error when the value at the key is not a sorted set + { + name: "4. Return error when the value at the key is not a sorted set", preset: true, presetValue: "Default value", key: "ZlexCountKey4", @@ -593,7 +631,8 @@ func Test_HandleZLEXCOUNT(t *testing.T) { expectedResponse: 0, expectedError: errors.New("value at ZlexCountKey4 is not a sorted set"), }, - { // 5. Command is too short + { + name: "5. Command is too short", preset: false, presetValue: nil, key: "ZlexCountKey5", @@ -602,7 +641,8 @@ func Test_HandleZLEXCOUNT(t *testing.T) { expectedResponse: 0, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 6. Command too long + { + name: "6. Command too long", preset: false, presetValue: nil, key: "ZlexCountKey6", @@ -614,47 +654,51 @@ func Test_HandleZLEXCOUNT(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZLEXCOUNT, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZLEXCOUNT, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleZLEXCOUNT(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + if err != nil { t.Error(err) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + rd := resp.NewReader(bytes.NewReader(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleZLEXCOUNT(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response %d at key \"%s\", got %d", test.expectedResponse, test.key, rv.Integer()) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewReader(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response %d at key \"%s\", got %d", test.expectedResponse, test.key, rv.Integer()) - } + }) } } func Test_HandleZDIFF(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} command []string expectedResponse [][]string expectedError error }{ - { // 1. Get the difference between 2 sorted sets without scores. + { + name: "1. Get the difference between 2 sorted sets without scores.", preset: true, presetValues: map[string]interface{}{ "ZdiffKey1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -676,7 +720,8 @@ func Test_HandleZDIFF(t *testing.T) { expectedResponse: [][]string{{"one"}, {"two"}}, expectedError: nil, }, - { // 2. Get the difference between 2 sorted sets with scores. + { + name: "2. Get the difference between 2 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZdiffKey1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -698,7 +743,8 @@ func Test_HandleZDIFF(t *testing.T) { expectedResponse: [][]string{{"one", "1"}, {"two", "2"}}, expectedError: nil, }, - { // 3. Get the difference between 3 sets with scores. + { + name: "3. Get the difference between 3 sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZdiffKey3": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -722,7 +768,8 @@ func Test_HandleZDIFF(t *testing.T) { expectedResponse: [][]string{{"three", "3"}, {"four", "4"}, {"five", "5"}, {"six", "6"}}, expectedError: nil, }, - { // 3. Return sorted set if only one key exists and is a sorted set + { + name: "4. Return sorted set if only one key exists and is a sorted set", preset: true, presetValues: map[string]interface{}{ "ZdiffKey6": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -739,7 +786,8 @@ func Test_HandleZDIFF(t *testing.T) { }, expectedError: nil, }, - { // 4. Throw error when one of the keys is not a sorted set. + { + name: "5. Throw error when one of the keys is not a sorted set.", preset: true, presetValues: map[string]interface{}{ "ZdiffKey9": "Default value", @@ -758,7 +806,8 @@ func Test_HandleZDIFF(t *testing.T) { expectedResponse: nil, expectedError: errors.New("value at ZdiffKey9 is not a sorted set"), }, - { // 6. Command too short + { + name: "6. Command too short", preset: false, command: []string{"ZDIFF"}, expectedResponse: [][]string{}, @@ -767,55 +816,58 @@ func Test_HandleZDIFF(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZDIFF, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZDIFF, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleZDIFF(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) + return } - } - res, err := handleZDIFF(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - for _, element := range rv.Array() { - if !slices.ContainsFunc(test.expectedResponse, func(expected []string) bool { - // The current sub-slice is a different length, return false because they're not equal - if len(element.Array()) != len(expected) { - return false - } - for i := 0; i < len(expected); i++ { - if element.Array()[i].String() != expected[i] { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) + } + for _, element := range rv.Array() { + if !slices.ContainsFunc(test.expectedResponse, func(expected []string) bool { + // The current sub-slice is a different length, return false because they're not equal + if len(element.Array()) != len(expected) { return false } + for i := 0; i < len(expected); i++ { + if element.Array()[i].String() != expected[i] { + return false + } + } + return true + }) { + t.Errorf("expected response %+v, got %+v", test.expectedResponse, rv.Array()) } - return true - }) { - t.Errorf("expected response %+v, got %+v", test.expectedResponse, rv.Array()) } - } + }) } } func Test_HandleZDIFFSTORE(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} destination string @@ -824,7 +876,8 @@ func Test_HandleZDIFFSTORE(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Get the difference between 2 sorted sets. + { + name: "1. Get the difference between 2 sorted sets.", preset: true, presetValues: map[string]interface{}{ "ZdiffStoreKey1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -844,7 +897,8 @@ func Test_HandleZDIFFSTORE(t *testing.T) { expectedResponse: 2, expectedError: nil, }, - { // 2. Get the difference between 3 sorted sets. + { + name: "2. Get the difference between 3 sorted sets.", preset: true, presetValues: map[string]interface{}{ "ZdiffStoreKey3": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -873,7 +927,8 @@ func Test_HandleZDIFFSTORE(t *testing.T) { expectedResponse: 4, expectedError: nil, }, - { // 3. Return base sorted set element if base set is the only existing key provided and is a valid sorted set + { + name: "3. Return base sorted set element if base set is the only existing key provided and is a valid sorted set", preset: true, presetValues: map[string]interface{}{ "ZdiffStoreKey6": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -894,7 +949,8 @@ func Test_HandleZDIFFSTORE(t *testing.T) { expectedResponse: 8, expectedError: nil, }, - { // 4. Throw error when base sorted set is not a set. + { + name: "4. Throw error when base sorted set is not a set.", preset: true, presetValues: map[string]interface{}{ "ZdiffStoreKey9": "Default value", @@ -915,7 +971,8 @@ func Test_HandleZDIFFSTORE(t *testing.T) { expectedResponse: 0, expectedError: errors.New("value at ZdiffStoreKey9 is not a sorted set"), }, - { // 5. Throw error when base set is non-existent. + { + name: "5. Throw error when base set is non-existent.", preset: true, destination: "ZdiffStoreDestinationKey5", presetValues: map[string]interface{}{ @@ -935,7 +992,8 @@ func Test_HandleZDIFFSTORE(t *testing.T) { expectedResponse: 0, expectedError: nil, }, - { // 6. Command too short + { + name: "6. Command too short", preset: false, command: []string{"ZDIFFSTORE", "ZdiffStoreDestinationKey6"}, expectedResponse: 0, @@ -944,57 +1002,60 @@ func Test_HandleZDIFFSTORE(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZDIFFSTORE, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZDIFFSTORE, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleZDIFFSTORE(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) + return } - } - res, err := handleZDIFFSTORE(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response integer %d, got %d", test.expectedResponse, rv.Integer()) - } - if test.expectedValue != nil { - if _, err = mockServer.KeyRLock(ctx, test.destination); err != nil { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - set, ok := mockServer.GetValue(ctx, test.destination).(*sorted_set.SortedSet) - if !ok { - t.Errorf("expected vaule at key %s to be set, got another type", test.destination) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response integer %d, got %d", test.expectedResponse, rv.Integer()) } - for _, elem := range set.GetAll() { - if !test.expectedValue.Contains(elem.Value) { - t.Errorf("could not find element %s in the expected values", elem.Value) + if test.expectedValue != nil { + if _, err = mockServer.KeyRLock(ctx, test.destination); err != nil { + t.Error(err) } + set, ok := mockServer.GetValue(ctx, test.destination).(*sorted_set.SortedSet) + if !ok { + t.Errorf("expected vaule at key %s to be set, got another type", test.destination) + } + for _, elem := range set.GetAll() { + if !test.expectedValue.Contains(elem.Value) { + t.Errorf("could not find element %s in the expected values", elem.Value) + } + } + mockServer.KeyRUnlock(ctx, test.destination) } - mockServer.KeyRUnlock(ctx, test.destination) - } + }) } } func Test_HandleZINCRBY(t *testing.T) { tests := []struct { + name string preset bool presetValue interface{} key string @@ -1003,7 +1064,8 @@ func Test_HandleZINCRBY(t *testing.T) { expectedResponse string expectedError error }{ - { // 1. Successfully increment by int. Return the new score + { + name: "1. Successfully increment by int. Return the new score", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, @@ -1020,7 +1082,8 @@ func Test_HandleZINCRBY(t *testing.T) { expectedResponse: "6", expectedError: nil, }, - { // 2. Successfully increment by float. Return new score + { + name: "2. Successfully increment by float. Return new score", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, @@ -1037,7 +1100,8 @@ func Test_HandleZINCRBY(t *testing.T) { expectedResponse: "347.785", expectedError: nil, }, - { // 3. Increment on non-existent sorted set will create the set with the member and increment as its score + { + name: "3. Increment on non-existent sorted set will create the set with the member and increment as its score", preset: false, presetValue: nil, key: "ZincrbyKey3", @@ -1048,7 +1112,8 @@ func Test_HandleZINCRBY(t *testing.T) { expectedResponse: "346.785", expectedError: nil, }, - { // 4. Increment score to +inf + { + name: "4. Increment score to +inf", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, @@ -1065,7 +1130,8 @@ func Test_HandleZINCRBY(t *testing.T) { expectedResponse: "+Inf", expectedError: nil, }, - { // 5. Increment score to -inf + { + name: "5. Increment score to -inf", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, @@ -1082,7 +1148,8 @@ func Test_HandleZINCRBY(t *testing.T) { expectedResponse: "-Inf", expectedError: nil, }, - { // 6. Incrementing score by negative increment should lower the score + { + name: "6. Incrementing score by negative increment should lower the score", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "one", Score: 1}, {Value: "two", Score: 2}, @@ -1099,7 +1166,8 @@ func Test_HandleZINCRBY(t *testing.T) { expectedResponse: "2.5", expectedError: nil, }, - { // 7. Return error when attempting to increment on a value that is not a valid sorted set + { + name: "7. Return error when attempting to increment on a value that is not a valid sorted set", preset: true, presetValue: "Default value", key: "ZincrbyKey7", @@ -1108,7 +1176,8 @@ func Test_HandleZINCRBY(t *testing.T) { expectedResponse: "", expectedError: errors.New("value at ZincrbyKey7 is not a sorted set"), }, - { // 8. Return error when trying to increment a member that already has score -inf + { + name: "8. Return error when trying to increment a member that already has score -inf", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "one", Score: sorted_set.Score(math.Inf(-1))}, @@ -1121,7 +1190,8 @@ func Test_HandleZINCRBY(t *testing.T) { expectedResponse: "", expectedError: errors.New("cannot increment -inf or +inf"), }, - { // 9. Return error when trying to increment a member that already has score +inf + { + name: "9. Return error when trying to increment a member that already has score +inf", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "one", Score: sorted_set.Score(math.Inf(1))}, @@ -1134,7 +1204,8 @@ func Test_HandleZINCRBY(t *testing.T) { expectedResponse: "", expectedError: errors.New("cannot increment -inf or +inf"), }, - { // 10. Return error when increment is not a valid number + { + name: "10. Return error when increment is not a valid number", preset: true, presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ {Value: "one", Score: 1}, @@ -1147,13 +1218,15 @@ func Test_HandleZINCRBY(t *testing.T) { expectedResponse: "", expectedError: errors.New("increment must be a double"), }, - { // 11. Command too short + { + name: "11. Command too short", key: "ZincrbyKey11", command: []string{"ZINCRBY", "ZincrbyKey11", "one"}, expectedResponse: "", expectedError: errors.New(constants.WrongArgsResponse), }, - { // 12. Command too long + { + name: "12. Command too long", key: "ZincrbyKey12", command: []string{"ZINCRBY", "ZincrbyKey12", "one", "1", "2"}, expectedResponse: "", @@ -1219,6 +1292,7 @@ func Test_HandleZINCRBY(t *testing.T) { func Test_HandleZMPOP(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} command []string @@ -1226,7 +1300,8 @@ func Test_HandleZMPOP(t *testing.T) { expectedResponse [][]string expectedError error }{ - { // 1. Successfully pop one min element by default + { + name: "1. Successfully pop one min element by default", preset: true, presetValues: map[string]interface{}{ "ZmpopKey1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -1248,7 +1323,8 @@ func Test_HandleZMPOP(t *testing.T) { }, expectedError: nil, }, - { // 2. Successfully pop one min element by specifying MIN + { + name: "2. Successfully pop one min element by specifying MIN", preset: true, presetValues: map[string]interface{}{ "ZmpopKey2": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -1270,7 +1346,8 @@ func Test_HandleZMPOP(t *testing.T) { }, expectedError: nil, }, - { // 3. Successfully pop one max element by specifying MAX modifier + { + name: "3. Successfully pop one max element by specifying MAX modifier", preset: true, presetValues: map[string]interface{}{ "ZmpopKey3": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -1291,7 +1368,8 @@ func Test_HandleZMPOP(t *testing.T) { }, expectedError: nil, }, - { // 4. Successfully pop multiple min elements + { + name: "4. Successfully pop multiple min elements", preset: true, presetValues: map[string]interface{}{ "ZmpopKey4": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -1312,7 +1390,8 @@ func Test_HandleZMPOP(t *testing.T) { }, expectedError: nil, }, - { // 5. Successfully pop multiple max elements + { + name: "5. Successfully pop multiple max elements", preset: true, presetValues: map[string]interface{}{ "ZmpopKey5": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -1330,7 +1409,8 @@ func Test_HandleZMPOP(t *testing.T) { expectedResponse: [][]string{{"two", "2"}, {"three", "3"}, {"four", "4"}, {"five", "5"}, {"six", "6"}}, expectedError: nil, }, - { // 6. Successfully pop elements from the first set which is non-empty + { + name: "6. Successfully pop elements from the first set which is non-empty", preset: true, presetValues: map[string]interface{}{ "ZmpopKey6": sorted_set.NewSortedSet([]sorted_set.MemberParam{}), @@ -1350,7 +1430,8 @@ func Test_HandleZMPOP(t *testing.T) { expectedResponse: [][]string{{"two", "2"}, {"three", "3"}, {"four", "4"}, {"five", "5"}, {"six", "6"}}, expectedError: nil, }, - { // 7. Skip the non-set items and pop elements from the first non-empty sorted set found + { + name: "7. Skip the non-set items and pop elements from the first non-empty sorted set found", preset: true, presetValues: map[string]interface{}{ "ZmpopKey8": "Default value", @@ -1372,12 +1453,14 @@ func Test_HandleZMPOP(t *testing.T) { expectedResponse: [][]string{{"one", "1"}, {"two", "2"}, {"three", "3"}, {"four", "4"}, {"five", "5"}}, expectedError: nil, }, - { // 9. Return error when count is a negative integer + { + name: "9. Return error when count is a negative integer", preset: false, command: []string{"ZMPOP", "ZmpopKey8", "MAX", "COUNT", "-20"}, expectedError: errors.New("count must be a positive integer"), }, - { // 9. Command too short + { + name: "9. Command too short", preset: false, command: []string{"ZMPOP"}, expectedError: errors.New(constants.WrongArgsResponse), @@ -1385,67 +1468,70 @@ func Test_HandleZMPOP(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZMPOP, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZMPOP, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleZMPOP(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) + return } - } - res, err := handleZMPOP(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - for _, element := range rv.Array() { - if !slices.ContainsFunc(test.expectedResponse, func(expected []string) bool { - // The current sub-slice is a different length, return false because they're not equal - if len(element.Array()) != len(expected) { - return false - } - for i := 0; i < len(expected); i++ { - if element.Array()[i].String() != expected[i] { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) + } + for _, element := range rv.Array() { + if !slices.ContainsFunc(test.expectedResponse, func(expected []string) bool { + // The current sub-slice is a different length, return false because they're not equal + if len(element.Array()) != len(expected) { return false } + for i := 0; i < len(expected); i++ { + if element.Array()[i].String() != expected[i] { + return false + } + } + return true + }) { + t.Errorf("expected response %+v, got %+v", test.expectedResponse, rv.Array()) } - return true - }) { - t.Errorf("expected response %+v, got %+v", test.expectedResponse, rv.Array()) - } - } - for key, expectedSortedSet := range test.expectedValues { - if _, err = mockServer.KeyRLock(ctx, key); err != nil { - t.Error(err) - } - set, ok := mockServer.GetValue(ctx, key).(*sorted_set.SortedSet) - if !ok { - t.Errorf("expected key \"%s\" to be a sorted set, got another type", key) } - if !set.Equals(expectedSortedSet) { - t.Errorf("expected sorted set at key \"%s\" %+v, got %+v", key, expectedSortedSet, set) + for key, expectedSortedSet := range test.expectedValues { + if _, err = mockServer.KeyRLock(ctx, key); err != nil { + t.Error(err) + } + set, ok := mockServer.GetValue(ctx, key).(*sorted_set.SortedSet) + if !ok { + t.Errorf("expected key \"%s\" to be a sorted set, got another type", key) + } + if !set.Equals(expectedSortedSet) { + t.Errorf("expected sorted set at key \"%s\" %+v, got %+v", key, expectedSortedSet, set) + } } - } + }) } } func Test_HandleZPOP(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} command []string @@ -1453,7 +1539,8 @@ func Test_HandleZPOP(t *testing.T) { expectedResponse [][]string expectedError error }{ - { // 1. Successfully pop one min element by default + { + name: "1. Successfully pop one min element by default", preset: true, presetValues: map[string]interface{}{ "ZmpopMinKey1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -1475,7 +1562,8 @@ func Test_HandleZPOP(t *testing.T) { }, expectedError: nil, }, - { // 2. Successfully pop one max element by default + { + name: "2. Successfully pop one max element by default", preset: true, presetValues: map[string]interface{}{ "ZmpopMaxKey2": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -1496,7 +1584,8 @@ func Test_HandleZPOP(t *testing.T) { }, expectedError: nil, }, - { // 3. Successfully pop multiple min elements + { + name: "3. Successfully pop multiple min elements", preset: true, presetValues: map[string]interface{}{ "ZmpopMinKey3": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -1517,7 +1606,8 @@ func Test_HandleZPOP(t *testing.T) { }, expectedError: nil, }, - { // 4. Successfully pop multiple max elements + { + name: "4. Successfully pop multiple max elements", preset: true, presetValues: map[string]interface{}{ "ZmpopMaxKey4": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -1535,7 +1625,8 @@ func Test_HandleZPOP(t *testing.T) { expectedResponse: [][]string{{"two", "2"}, {"three", "3"}, {"four", "4"}, {"five", "5"}, {"six", "6"}}, expectedError: nil, }, - { // 5. Throw an error when trying to pop from an element that's not a sorted set + { + name: "5. Throw an error when trying to pop from an element that's not a sorted set", preset: true, presetValues: map[string]interface{}{ "ZmpopMinKey5": "Default value", @@ -1545,12 +1636,14 @@ func Test_HandleZPOP(t *testing.T) { expectedResponse: nil, expectedError: errors.New("value at key ZmpopMinKey5 is not a sorted set"), }, - { // 6. Command too short + { + name: "6. Command too short", preset: false, command: []string{"ZPOPMAX"}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 7. Command too long + { + name: "7. Command too long", preset: false, command: []string{"ZPOPMAX", "ZmpopMaxKey7", "6", "3"}, expectedError: errors.New(constants.WrongArgsResponse), @@ -1558,75 +1651,80 @@ func Test_HandleZPOP(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZPOPMIN/ZPOPMAX, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZPOPMIN/ZPOPMAX, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleZPOP(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) + return } - } - res, err := handleZPOP(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - for _, element := range rv.Array() { - if !slices.ContainsFunc(test.expectedResponse, func(expected []string) bool { - // The current sub-slice is a different length, return false because they're not equal - if len(element.Array()) != len(expected) { - return false - } - for i := 0; i < len(expected); i++ { - if element.Array()[i].String() != expected[i] { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) + } + for _, element := range rv.Array() { + if !slices.ContainsFunc(test.expectedResponse, func(expected []string) bool { + // The current sub-slice is a different length, return false because they're not equal + if len(element.Array()) != len(expected) { return false } + for i := 0; i < len(expected); i++ { + if element.Array()[i].String() != expected[i] { + return false + } + } + return true + }) { + t.Errorf("expected response %+v, got %+v", test.expectedResponse, rv.Array()) } - return true - }) { - t.Errorf("expected response %+v, got %+v", test.expectedResponse, rv.Array()) - } - } - for key, expectedSortedSet := range test.expectedValues { - if _, err = mockServer.KeyRLock(ctx, key); err != nil { - t.Error(err) } - set, ok := mockServer.GetValue(ctx, key).(*sorted_set.SortedSet) - if !ok { - t.Errorf("expected key \"%s\" to be a sorted set, got another type", key) - } - if !set.Equals(expectedSortedSet) { - t.Errorf("expected sorted set at key \"%s\" %+v, got %+v", key, expectedSortedSet, set) + for key, expectedSortedSet := range test.expectedValues { + if _, err = mockServer.KeyRLock(ctx, key); err != nil { + t.Error(err) + } + set, ok := mockServer.GetValue(ctx, key).(*sorted_set.SortedSet) + if !ok { + t.Errorf("expected key \"%s\" to be a sorted set, got another type", key) + } + if !set.Equals(expectedSortedSet) { + t.Errorf("expected sorted set at key \"%s\" %+v, got %+v", key, expectedSortedSet, set) + } } - } + }) } } func Test_HandleZMSCORE(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} command []string expectedResponse []interface{} expectedError error }{ - { // 1. Return multiple scores from the sorted set. + { + // 1. Return multiple scores from the sorted set. // Return nil for elements that do not exist in the sorted set. + name: "Return multiple scores from the sorted set.", preset: true, presetValues: map[string]interface{}{ "ZmScoreKey1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -1639,20 +1737,23 @@ func Test_HandleZMSCORE(t *testing.T) { expectedResponse: []interface{}{"1.1", nil, "245", "1.1", "3", "4.055", nil, "5"}, expectedError: nil, }, - { // 2. If key does not exist, return empty array + { + name: "2. If key does not exist, return empty array", preset: false, presetValues: nil, command: []string{"ZMSCORE", "ZmScoreKey2", "one", "two", "three", "four"}, expectedResponse: []interface{}{}, expectedError: nil, }, - { // 3. Throw error when trying to find scores from elements that are not sorted sets + { + name: "3. Throw error when trying to find scores from elements that are not sorted sets", preset: true, presetValues: map[string]interface{}{"ZmScoreKey3": "Default value"}, command: []string{"ZMSCORE", "ZmScoreKey3", "one", "two", "three"}, expectedError: errors.New("value at ZmScoreKey3 is not a sorted set"), }, - { // 9. Command too short + { + name: "9. Command too short", preset: false, command: []string{"ZMSCORE"}, expectedError: errors.New(constants.WrongArgsResponse), @@ -1660,57 +1761,61 @@ func Test_HandleZMSCORE(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZMSCORE, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZMSCORE, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleZMSCORE(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) + return } - } - res, err := handleZMSCORE(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - for i := 0; i < len(rv.Array()); i++ { - if rv.Array()[i].IsNull() { - if test.expectedResponse[i] != nil { - t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedResponse[i], rv.Array()[i]) - } - continue + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - if rv.Array()[i].String() != test.expectedResponse[i] { - t.Errorf("expected \"%s\" at index %d, got %s", test.expectedResponse[i], i, rv.Array()[i].String()) + for i := 0; i < len(rv.Array()); i++ { + if rv.Array()[i].IsNull() { + if test.expectedResponse[i] != nil { + t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedResponse[i], rv.Array()[i]) + } + continue + } + if rv.Array()[i].String() != test.expectedResponse[i] { + t.Errorf("expected \"%s\" at index %d, got %s", test.expectedResponse[i], i, rv.Array()[i].String()) + } } - } + }) } } func Test_HandleZSCORE(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} command []string expectedResponse interface{} expectedError error }{ - { // 1. Return score from a sorted set. + { + name: "1. Return score from a sorted set.", preset: true, presetValues: map[string]interface{}{ "ZscoreKey1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -1723,14 +1828,16 @@ func Test_HandleZSCORE(t *testing.T) { expectedResponse: "4.055", expectedError: nil, }, - { // 2. If key does not exist, return nil value + { + name: "2. If key does not exist, return nil value", preset: false, presetValues: nil, command: []string{"ZSCORE", "ZscoreKey2", "one"}, expectedResponse: nil, expectedError: nil, }, - { // 3. If key exists and is a sorted set, but the member does not exist, return nil + { + name: "3. If key exists and is a sorted set, but the member does not exist, return nil", preset: true, presetValues: map[string]interface{}{ "ZscoreKey3": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -1743,18 +1850,21 @@ func Test_HandleZSCORE(t *testing.T) { expectedResponse: nil, expectedError: nil, }, - { // 4. Throw error when trying to find scores from elements that are not sorted sets + { + name: "4. Throw error when trying to find scores from elements that are not sorted sets", preset: true, presetValues: map[string]interface{}{"ZscoreKey4": "Default value"}, command: []string{"ZSCORE", "ZscoreKey4", "one"}, expectedError: errors.New("value at ZscoreKey4 is not a sorted set"), }, - { // 5. Command too short + { + name: "5. Command too short", preset: false, command: []string{"ZSCORE"}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 6. Command too long + { + name: "6. Command too long", preset: false, command: []string{"ZSCORE", "ZscoreKey5", "one", "two"}, expectedError: errors.New(constants.WrongArgsResponse), @@ -1762,48 +1872,51 @@ func Test_HandleZSCORE(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZSCORE, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZSCORE, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleZSCORE(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) + return } - } - res, err := handleZSCORE(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if test.expectedResponse == nil { - if !rv.IsNull() { - t.Errorf("expected nil response, got %+v", rv) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - continue - } - if rv.String() != test.expectedResponse { - t.Errorf("expected response \"%s\", got %s", test.expectedResponse, rv.String()) - } + if test.expectedResponse == nil { + if !rv.IsNull() { + t.Errorf("expected nil response, got %+v", rv) + } + return + } + if rv.String() != test.expectedResponse { + t.Errorf("expected response \"%s\", got %s", test.expectedResponse, rv.String()) + } + }) } } func Test_HandleZRANDMEMBER(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -1813,8 +1926,10 @@ func Test_HandleZRANDMEMBER(t *testing.T) { expectedResponse [][]string expectedError error }{ - { // 1. Return multiple random elements without removing them + { + // 1. Return multiple random elements without removing them. // Count is positive, do not allow repeated elements + name: "1. Return multiple random elements without removing them.", preset: true, key: "ZrandMemberKey1", presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -1833,6 +1948,7 @@ func Test_HandleZRANDMEMBER(t *testing.T) { { // 2. Return multiple random elements and their scores without removing them. // Count is negative, so allow repeated numbers. + name: "2. Return multiple random elements and their scores without removing them.", preset: true, key: "ZrandMemberKey2", presetValue: sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -1848,7 +1964,8 @@ func Test_HandleZRANDMEMBER(t *testing.T) { }, expectedError: nil, }, - { // 2. Return error when the source key is not a sorted set. + { + name: "2. Return error when the source key is not a sorted set.", preset: true, key: "ZrandMemberKey3", presetValue: "Default value", @@ -1856,22 +1973,26 @@ func Test_HandleZRANDMEMBER(t *testing.T) { expectedValue: 0, expectedError: errors.New("value at ZrandMemberKey3 is not a sorted set"), }, - { // 5. Command too short + { + name: "5. Command too short", preset: false, command: []string{"ZRANDMEMBER"}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 6. Command too long + { + name: "6. Command too long", preset: false, command: []string{"ZRANDMEMBER", "source5", "source6", "member1", "member2"}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 7. Throw error when count is not an integer + { + name: "7. Throw error when count is not an integer", preset: false, command: []string{"ZRANDMEMBER", "ZrandMemberKey1", "count"}, expectedError: errors.New("count must be an integer"), }, - { // 8. Throw error when the fourth argument is not WITHSCORES + { + name: "8. Throw error when the fourth argument is not WITHSCORES", preset: false, command: []string{"ZRANDMEMBER", "ZrandMemberKey1", "8", "ANOTHER"}, expectedError: errors.New("last option must be WITHSCORES"), @@ -1879,99 +2000,103 @@ func Test_HandleZRANDMEMBER(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZRANDMEMBER, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZRANDMEMBER, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { - t.Error(err) + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + res, err := handleZRANDMEMBER(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleZRANDMEMBER(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - // 1. Check if the response array members are all included in test.expectedResponse. - for _, element := range rv.Array() { - if !slices.ContainsFunc(test.expectedResponse, func(expected []string) bool { - // The current sub-slice is a different length, return false because they're not equal - if len(element.Array()) != len(expected) { - return false - } - for i := 0; i < len(expected); i++ { - if element.Array()[i].String() != expected[i] { + // 1. Check if the response array members are all included in test.expectedResponse. + for _, element := range rv.Array() { + if !slices.ContainsFunc(test.expectedResponse, func(expected []string) bool { + // The current sub-slice is a different length, return false because they're not equal + if len(element.Array()) != len(expected) { return false } + for i := 0; i < len(expected); i++ { + if element.Array()[i].String() != expected[i] { + return false + } + } + return true + }) { + t.Errorf("expected response %+v, got %+v", test.expectedResponse, rv.Array()) } - return true - }) { - t.Errorf("expected response %+v, got %+v", test.expectedResponse, rv.Array()) } - } - // 2. Fetch the set and check if its cardinality is what we expect. - if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { - t.Error(err) - } - set, ok := mockServer.GetValue(ctx, test.key).(*sorted_set.SortedSet) - if !ok { - t.Errorf("expected value at key \"%s\" to be a set, got another type", test.key) - } - if set.Cardinality() != test.expectedValue { - t.Errorf("expected cardinality of final set to be %d, got %d", test.expectedValue, set.Cardinality()) - } - // 3. Check if all the returned elements we received are still in the set. - for _, element := range rv.Array() { - if !set.Contains(sorted_set.Value(element.Array()[0].String())) { - t.Errorf("expected element \"%s\" to be in set but it was not found", element.String()) + // 2. Fetch the set and check if its cardinality is what we expect. + if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { + t.Error(err) } - } - // 4. If allowRepeat is false, check that all the elements make a valid set - if !test.allowRepeat { - var elems []sorted_set.MemberParam - for _, e := range rv.Array() { - if len(e.Array()) == 1 { + set, ok := mockServer.GetValue(ctx, test.key).(*sorted_set.SortedSet) + if !ok { + t.Errorf("expected value at key \"%s\" to be a set, got another type", test.key) + } + if set.Cardinality() != test.expectedValue { + t.Errorf("expected cardinality of final set to be %d, got %d", test.expectedValue, set.Cardinality()) + } + // 3. Check if all the returned elements we received are still in the set. + for _, element := range rv.Array() { + if !set.Contains(sorted_set.Value(element.Array()[0].String())) { + t.Errorf("expected element \"%s\" to be in set but it was not found", element.String()) + } + } + // 4. If allowRepeat is false, check that all the elements make a valid set + if !test.allowRepeat { + var elems []sorted_set.MemberParam + for _, e := range rv.Array() { + if len(e.Array()) == 1 { + elems = append(elems, sorted_set.MemberParam{ + Value: sorted_set.Value(e.Array()[0].String()), + Score: 1, + }) + continue + } elems = append(elems, sorted_set.MemberParam{ Value: sorted_set.Value(e.Array()[0].String()), - Score: 1, + Score: sorted_set.Score(e.Array()[1].Float()), }) - continue } - elems = append(elems, sorted_set.MemberParam{ - Value: sorted_set.Value(e.Array()[0].String()), - Score: sorted_set.Score(e.Array()[1].Float()), - }) - } - s := sorted_set.NewSortedSet(elems) - if s.Cardinality() != len(elems) { - t.Errorf("expected non-repeating elements for random elements at key \"%s\"", test.key) + s := sorted_set.NewSortedSet(elems) + if s.Cardinality() != len(elems) { + t.Errorf("expected non-repeating elements for random elements at key \"%s\"", test.key) + } } - } + }) } } func Test_HandleZRANK(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} command []string expectedResponse []string expectedError error }{ - { // 1. Return element's rank from a sorted set. + { + name: "1. Return element's rank from a sorted set.", preset: true, presetValues: map[string]interface{}{ "ZrankKey1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -1984,7 +2109,8 @@ func Test_HandleZRANK(t *testing.T) { expectedResponse: []string{"3"}, expectedError: nil, }, - { // 2. Return element's rank from a sorted set with its score. + { + name: "2. Return element's rank from a sorted set with its score.", preset: true, presetValues: map[string]interface{}{ "ZrankKey1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -1997,14 +2123,16 @@ func Test_HandleZRANK(t *testing.T) { expectedResponse: []string{"3", "411.055"}, expectedError: nil, }, - { // 3. If key does not exist, return nil value + { + name: "3. If key does not exist, return nil value", preset: false, presetValues: nil, command: []string{"ZRANK", "ZrankKey3", "one"}, expectedResponse: nil, expectedError: nil, }, - { // 4. If key exists and is a sorted set, but the member does not exist, return nil + { + name: "4. If key exists and is a sorted set, but the member does not exist, return nil", preset: true, presetValues: map[string]interface{}{ "ZrankKey4": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2017,18 +2145,21 @@ func Test_HandleZRANK(t *testing.T) { expectedResponse: nil, expectedError: nil, }, - { // 5. Throw error when trying to find scores from elements that are not sorted sets + { + name: "5. Throw error when trying to find scores from elements that are not sorted sets", preset: true, presetValues: map[string]interface{}{"ZrankKey5": "Default value"}, command: []string{"ZRANK", "ZrankKey5", "one"}, expectedError: errors.New("value at ZrankKey5 is not a sorted set"), }, - { // 5. Command too short + { + name: "5. Command too short", preset: false, command: []string{"ZRANK"}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 6. Command too long + { + name: "6. Command too long", preset: false, command: []string{"ZRANK", "ZrankKey5", "one", "WITHSCORES", "two"}, expectedError: errors.New(constants.WrongArgsResponse), @@ -2036,53 +2167,56 @@ func Test_HandleZRANK(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZRANK, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZRANK, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleZRANK(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) + return } - } - res, err := handleZRANK(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if test.expectedResponse == nil { - if !rv.IsNull() { - t.Errorf("expected nil response, got %+v", rv) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - continue - } - if len(rv.Array()) != len(test.expectedResponse) { - t.Errorf("expected response %+v, got %+v", test.expectedResponse, rv.Array()) - } - for i := 0; i < len(test.expectedResponse); i++ { - if rv.Array()[i].String() != test.expectedResponse[i] { - t.Errorf("expected element at index %d to be %s, got %s", i, test.expectedResponse[i], rv.Array()[i].String()) + if test.expectedResponse == nil { + if !rv.IsNull() { + t.Errorf("expected nil response, got %+v", rv) + } + return } - } + if len(rv.Array()) != len(test.expectedResponse) { + t.Errorf("expected response %+v, got %+v", test.expectedResponse, rv.Array()) + } + for i := 0; i < len(test.expectedResponse); i++ { + if rv.Array()[i].String() != test.expectedResponse[i] { + t.Errorf("expected element at index %d to be %s, got %s", i, test.expectedResponse[i], rv.Array()[i].String()) + } + } + }) } } func Test_HandleZREM(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} command []string @@ -2090,8 +2224,10 @@ func Test_HandleZREM(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Successfully remove multiple elements from sorted set, skipping non-existent members. + { + // Successfully remove multiple elements from sorted set, skipping non-existent members. // Return deleted count. + name: "1. Successfully remove multiple elements from sorted set, skipping non-existent members.", preset: true, presetValues: map[string]interface{}{ "ZremKey1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2112,7 +2248,8 @@ func Test_HandleZREM(t *testing.T) { expectedResponse: 5, expectedError: nil, }, - { // 2. If key does not exist, return 0 + { + name: "2. If key does not exist, return 0", preset: false, presetValues: nil, command: []string{"ZREM", "ZremKey2", "member"}, @@ -2120,7 +2257,8 @@ func Test_HandleZREM(t *testing.T) { expectedResponse: 0, expectedError: nil, }, - { // 3. Return error key is not a sorted set + { + name: "3. Return error key is not a sorted set", preset: true, presetValues: map[string]interface{}{ "ZremKey3": "Default value", @@ -2128,7 +2266,8 @@ func Test_HandleZREM(t *testing.T) { command: []string{"ZREM", "ZremKey3", "member"}, expectedError: errors.New("value at ZremKey3 is not a sorted set"), }, - { // 9. Command too short + { + name: "9. Command too short", preset: false, command: []string{"ZREM"}, expectedError: errors.New(constants.WrongArgsResponse), @@ -2136,57 +2275,60 @@ func Test_HandleZREM(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZREM, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZREM, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleZREM(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) + return } - } - res, err := handleZREM(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) - } - // Check if the expected sorted set is the same at the current one - if test.expectedValues != nil { - for key, expectedSet := range test.expectedValues { - if _, err = mockServer.KeyRLock(ctx, key); err != nil { - t.Error(err) - } - set, ok := mockServer.GetValue(ctx, key).(*sorted_set.SortedSet) - if !ok { - t.Errorf("expected value at key \"%s\" to be a sorted set, got another type", key) - } - if !set.Equals(expectedSet) { - t.Errorf("exptected sorted set %+v, got %+v", expectedSet, set) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) + } + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) + } + // Check if the expected sorted set is the same at the current one + if test.expectedValues != nil { + for key, expectedSet := range test.expectedValues { + if _, err = mockServer.KeyRLock(ctx, key); err != nil { + t.Error(err) + } + set, ok := mockServer.GetValue(ctx, key).(*sorted_set.SortedSet) + if !ok { + t.Errorf("expected value at key \"%s\" to be a sorted set, got another type", key) + } + if !set.Equals(expectedSet) { + t.Errorf("exptected sorted set %+v, got %+v", expectedSet, set) + } } } - } + }) } } func Test_HandleZREMRANGEBYSCORE(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} command []string @@ -2194,7 +2336,8 @@ func Test_HandleZREMRANGEBYSCORE(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Successfully remove multiple elements with scores inside the provided range + { + name: "1. Successfully remove multiple elements with scores inside the provided range", preset: true, presetValues: map[string]interface{}{ "ZremRangeByScoreKey1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2215,7 +2358,8 @@ func Test_HandleZREMRANGEBYSCORE(t *testing.T) { expectedResponse: 5, expectedError: nil, }, - { // 2. If key does not exist, return 0 + { + name: "2. If key does not exist, return 0", preset: false, presetValues: nil, command: []string{"ZREMRANGEBYSCORE", "ZremRangeByScoreKey2", "2", "4"}, @@ -2223,7 +2367,8 @@ func Test_HandleZREMRANGEBYSCORE(t *testing.T) { expectedResponse: 0, expectedError: nil, }, - { // 3. Return error key is not a sorted set + { + name: "3. Return error key is not a sorted set", preset: true, presetValues: map[string]interface{}{ "ZremRangeByScoreKey3": "Default value", @@ -2231,12 +2376,14 @@ func Test_HandleZREMRANGEBYSCORE(t *testing.T) { command: []string{"ZREMRANGEBYSCORE", "ZremRangeByScoreKey3", "4", "4"}, expectedError: errors.New("value at ZremRangeByScoreKey3 is not a sorted set"), }, - { // 4. Command too short + { + name: "4. Command too short", preset: false, command: []string{"ZREMRANGEBYSCORE", "ZremRangeByScoreKey4", "3"}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 5. Command too long + { + name: "5. Command too long", preset: false, command: []string{"ZREMRANGEBYSCORE", "ZremRangeByScoreKey5", "4", "5", "8"}, expectedError: errors.New(constants.WrongArgsResponse), @@ -2244,57 +2391,60 @@ func Test_HandleZREMRANGEBYSCORE(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZREMRANGEBYSCORE, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZREMRANGEBYSCORE, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleZREMRANGEBYSCORE(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) + return } - } - res, err := handleZREMRANGEBYSCORE(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) - } - // Check if the expected values are the same - if test.expectedValues != nil { - for key, expectedSet := range test.expectedValues { - if _, err = mockServer.KeyRLock(ctx, key); err != nil { - t.Error(err) - } - set, ok := mockServer.GetValue(ctx, key).(*sorted_set.SortedSet) - if !ok { - t.Errorf("expected value at key \"%s\" to be a sorted set, got another type", key) - } - if !set.Equals(expectedSet) { - t.Errorf("exptected sorted set %+v, got %+v", expectedSet, set) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) + } + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) + } + // Check if the expected values are the same + if test.expectedValues != nil { + for key, expectedSet := range test.expectedValues { + if _, err = mockServer.KeyRLock(ctx, key); err != nil { + t.Error(err) + } + set, ok := mockServer.GetValue(ctx, key).(*sorted_set.SortedSet) + if !ok { + t.Errorf("expected value at key \"%s\" to be a sorted set, got another type", key) + } + if !set.Equals(expectedSet) { + t.Errorf("exptected sorted set %+v, got %+v", expectedSet, set) + } } } - } + }) } } func Test_HandleZREMRANGEBYRANK(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} command []string @@ -2302,7 +2452,8 @@ func Test_HandleZREMRANGEBYRANK(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Successfully remove multiple elements within range + { + name: "1. Successfully remove multiple elements within range", preset: true, presetValues: map[string]interface{}{ "ZremRangeByRankKey1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2323,7 +2474,8 @@ func Test_HandleZREMRANGEBYRANK(t *testing.T) { expectedResponse: 6, expectedError: nil, }, - { // 2. Establish boundaries from the end of the set when negative boundaries are provided + { + name: "2. Establish boundaries from the end of the set when negative boundaries are provided", preset: true, presetValues: map[string]interface{}{ "ZremRangeByRankKey2": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2345,7 +2497,8 @@ func Test_HandleZREMRANGEBYRANK(t *testing.T) { expectedResponse: 4, expectedError: nil, }, - { // 2. If key does not exist, return 0 + { + name: "2. If key does not exist, return 0", preset: false, presetValues: nil, command: []string{"ZREMRANGEBYRANK", "ZremRangeByRankKey3", "2", "4"}, @@ -2353,7 +2506,8 @@ func Test_HandleZREMRANGEBYRANK(t *testing.T) { expectedResponse: 0, expectedError: nil, }, - { // 3. Return error key is not a sorted set + { + name: "3. Return error key is not a sorted set", preset: true, presetValues: map[string]interface{}{ "ZremRangeByRankKey3": "Default value", @@ -2361,12 +2515,14 @@ func Test_HandleZREMRANGEBYRANK(t *testing.T) { command: []string{"ZREMRANGEBYRANK", "ZremRangeByRankKey3", "4", "4"}, expectedError: errors.New("value at ZremRangeByRankKey3 is not a sorted set"), }, - { // 4. Command too short + { + name: "4. Command too short", preset: false, command: []string{"ZREMRANGEBYRANK", "ZremRangeByRankKey4", "3"}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 5. Return error when start index is out of bounds + { + name: "5. Return error when start index is out of bounds", preset: true, presetValues: map[string]interface{}{ "ZremRangeByRankKey5": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2382,7 +2538,8 @@ func Test_HandleZREMRANGEBYRANK(t *testing.T) { expectedResponse: 0, expectedError: errors.New("indices out of bounds"), }, - { // 6. Return error when end index is out of bounds + { + name: "6. Return error when end index is out of bounds", preset: true, presetValues: map[string]interface{}{ "ZremRangeByRankKey6": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2398,7 +2555,8 @@ func Test_HandleZREMRANGEBYRANK(t *testing.T) { expectedResponse: 0, expectedError: errors.New("indices out of bounds"), }, - { // 7. Command too long + { + name: "7. Command too long", preset: false, command: []string{"ZREMRANGEBYRANK", "ZremRangeByRankKey7", "4", "5", "8"}, expectedError: errors.New(constants.WrongArgsResponse), @@ -2406,57 +2564,60 @@ func Test_HandleZREMRANGEBYRANK(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZREMRANGEBYRANK, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZREMRANGEBYRANK, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleZREMRANGEBYRANK(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) + return } - } - res, err := handleZREMRANGEBYRANK(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) - } - // Check if the expected values are the same - if test.expectedValues != nil { - for key, expectedSet := range test.expectedValues { - if _, err = mockServer.KeyRLock(ctx, key); err != nil { - t.Error(err) - } - set, ok := mockServer.GetValue(ctx, key).(*sorted_set.SortedSet) - if !ok { - t.Errorf("expected value at key \"%s\" to be a sorted set, got another type", key) - } - if !set.Equals(expectedSet) { - t.Errorf("exptected sorted set %+v, got %+v", expectedSet, set) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) + } + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) + } + // Check if the expected values are the same + if test.expectedValues != nil { + for key, expectedSet := range test.expectedValues { + if _, err = mockServer.KeyRLock(ctx, key); err != nil { + t.Error(err) + } + set, ok := mockServer.GetValue(ctx, key).(*sorted_set.SortedSet) + if !ok { + t.Errorf("expected value at key \"%s\" to be a sorted set, got another type", key) + } + if !set.Equals(expectedSet) { + t.Errorf("exptected sorted set %+v, got %+v", expectedSet, set) + } } } - } + }) } } func Test_HandleZREMRANGEBYLEX(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} command []string @@ -2464,7 +2625,8 @@ func Test_HandleZREMRANGEBYLEX(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Successfully remove multiple elements with scores inside the provided range + { + name: "1. Successfully remove multiple elements with scores inside the provided range", preset: true, presetValues: map[string]interface{}{ "ZremRangeByLexKey1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2486,7 +2648,8 @@ func Test_HandleZREMRANGEBYLEX(t *testing.T) { expectedResponse: 4, expectedError: nil, }, - { // 2. Return 0 if the members do not have the same score + { + name: "2. Return 0 if the members do not have the same score", preset: true, presetValues: map[string]interface{}{ "ZremRangeByLexKey2": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2510,7 +2673,8 @@ func Test_HandleZREMRANGEBYLEX(t *testing.T) { expectedResponse: 0, expectedError: nil, }, - { // 3. If key does not exist, return 0 + { + name: "3. If key does not exist, return 0", preset: false, presetValues: nil, command: []string{"ZREMRANGEBYLEX", "ZremRangeByLexKey3", "2", "4"}, @@ -2518,7 +2682,8 @@ func Test_HandleZREMRANGEBYLEX(t *testing.T) { expectedResponse: 0, expectedError: nil, }, - { // 3. Return error key is not a sorted set + { + name: "3. Return error key is not a sorted set", preset: true, presetValues: map[string]interface{}{ "ZremRangeByLexKey3": "Default value", @@ -2526,77 +2691,83 @@ func Test_HandleZREMRANGEBYLEX(t *testing.T) { command: []string{"ZREMRANGEBYLEX", "ZremRangeByLexKey3", "a", "d"}, expectedError: errors.New("value at ZremRangeByLexKey3 is not a sorted set"), }, - { // 4. Command too short + { + name: "4. Command too short", preset: false, command: []string{"ZREMRANGEBYLEX", "ZremRangeByLexKey4", "a"}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 5. Command too long + { + name: "5. Command too long", preset: false, command: []string{"ZREMRANGEBYLEX", "ZremRangeByLexKey5", "a", "b", "c"}, expectedError: errors.New(constants.WrongArgsResponse), }, } - for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZREMRANGEBYLEX, %d", i)) - - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) - } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) - } - mockServer.KeyUnlock(ctx, key) - } - } - res, err := handleZREMRANGEBYLEX(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) - } - // Check if the expected values are the same - if test.expectedValues != nil { - for key, expectedSet := range test.expectedValues { - if _, err = mockServer.KeyRLock(ctx, key); err != nil { - t.Error(err) + for i, test := range tests { + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZREMRANGEBYLEX, %d", i)) + + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - set, ok := mockServer.GetValue(ctx, key).(*sorted_set.SortedSet) - if !ok { - t.Errorf("expected value at key \"%s\" to be a sorted set, got another type", key) + } + res, err := handleZREMRANGEBYLEX(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - if !set.Equals(expectedSet) { - t.Errorf("exptected sorted set %+v, got %+v", expectedSet, set) + return + } + if err != nil { + t.Error(err) + } + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) + } + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) + } + // Check if the expected values are the same + if test.expectedValues != nil { + for key, expectedSet := range test.expectedValues { + if _, err = mockServer.KeyRLock(ctx, key); err != nil { + t.Error(err) + } + set, ok := mockServer.GetValue(ctx, key).(*sorted_set.SortedSet) + if !ok { + t.Errorf("expected value at key \"%s\" to be a sorted set, got another type", key) + } + if !set.Equals(expectedSet) { + t.Errorf("exptected sorted set %+v, got %+v", expectedSet, set) + } } } - } + }) } } func Test_HandleZRANGE(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} command []string expectedResponse [][]string expectedError error }{ - { // 1. Get elements withing score range without score. + { + name: "1. Get elements withing score range without score.", preset: true, presetValues: map[string]interface{}{ "ZrangeKey1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2610,7 +2781,8 @@ func Test_HandleZRANGE(t *testing.T) { expectedResponse: [][]string{{"three"}, {"four"}, {"five"}, {"six"}, {"seven"}}, expectedError: nil, }, - { // 2. Get elements within score range with score. + { + name: "2. Get elements within score range with score.", preset: true, presetValues: map[string]interface{}{ "ZrangeKey2": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2626,8 +2798,10 @@ func Test_HandleZRANGE(t *testing.T) { {"six", "6"}, {"seven", "7"}}, expectedError: nil, }, - { // 3. Get elements within score range with offset and limit. + { + // 3. Get elements within score range with offset and limit. // Offset and limit are in where we start and stop counting in the original sorted set (NOT THE RESULT). + name: "3. Get elements within score range with offset and limit.", preset: true, presetValues: map[string]interface{}{ "ZrangeKey3": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2641,9 +2815,11 @@ func Test_HandleZRANGE(t *testing.T) { expectedResponse: [][]string{{"three", "3"}, {"four", "4"}, {"five", "5"}}, expectedError: nil, }, - { // 4. Get elements within score range with offset and limit + reverse the results. + { + // 4. Get elements within score range with offset and limit + reverse the results. // Offset and limit are in where we start and stop counting in the original sorted set (NOT THE RESULT). // REV reverses the original set before getting the range. + name: "4. Get elements within score range with offset and limit + reverse the results.", preset: true, presetValues: map[string]interface{}{ "ZrangeKey4": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2657,7 +2833,8 @@ func Test_HandleZRANGE(t *testing.T) { expectedResponse: [][]string{{"six", "6"}, {"five", "5"}, {"four", "4"}}, expectedError: nil, }, - { // 5. Get elements within lex range without score. + { + name: "5. Get elements within lex range without score.", preset: true, presetValues: map[string]interface{}{ "ZrangeKey5": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2671,7 +2848,8 @@ func Test_HandleZRANGE(t *testing.T) { expectedResponse: [][]string{{"c"}, {"d"}, {"e"}, {"f"}, {"g"}}, expectedError: nil, }, - { // 6. Get elements within lex range with score. + { + name: "6. Get elements within lex range with score.", preset: true, presetValues: map[string]interface{}{ "ZrangeKey6": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2687,8 +2865,10 @@ func Test_HandleZRANGE(t *testing.T) { {"d", "1"}, {"e", "1"}, {"f", "1"}}, expectedError: nil, }, - { // 7. Get elements within lex range with offset and limit. + { + // 7. Get elements within lex range with offset and limit. // Offset and limit are in where we start and stop counting in the original sorted set (NOT THE RESULT). + name: "7. Get elements within lex range with offset and limit.", preset: true, presetValues: map[string]interface{}{ "ZrangeKey7": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2702,9 +2882,11 @@ func Test_HandleZRANGE(t *testing.T) { expectedResponse: [][]string{{"c", "1"}, {"d", "1"}, {"e", "1"}}, expectedError: nil, }, - { // 8. Get elements within lex range with offset and limit + reverse the results. + { + // 8. Get elements within lex range with offset and limit + reverse the results. // Offset and limit are in where we start and stop counting in the original sorted set (NOT THE RESULT). // REV reverses the original set before getting the range. + name: "8. Get elements within lex range with offset and limit + reverse the results.", preset: true, presetValues: map[string]interface{}{ "ZrangeKey8": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2718,7 +2900,8 @@ func Test_HandleZRANGE(t *testing.T) { expectedResponse: [][]string{{"f", "1"}, {"e", "1"}, {"d", "1"}}, expectedError: nil, }, - { // 9. Return an empty slice when we use BYLEX while elements have different scores + { + name: "9. Return an empty slice when we use BYLEX while elements have different scores", preset: true, presetValues: map[string]interface{}{ "ZrangeKey9": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2732,35 +2915,40 @@ func Test_HandleZRANGE(t *testing.T) { expectedResponse: [][]string{}, expectedError: nil, }, - { // 10. Throw error when limit does not provide both offset and limit + { + name: "10. Throw error when limit does not provide both offset and limit", preset: false, presetValues: nil, command: []string{"ZRANGE", "ZrangeKey10", "a", "h", "BYLEX", "WITHSCORES", "LIMIT", "2"}, expectedResponse: [][]string{}, expectedError: errors.New("limit should contain offset and count as integers"), }, - { // 11. Throw error when offset is not a valid integer + { + name: "11. Throw error when offset is not a valid integer", preset: false, presetValues: nil, command: []string{"ZRANGE", "ZrangeKey11", "a", "h", "BYLEX", "WITHSCORES", "LIMIT", "offset", "4"}, expectedResponse: [][]string{}, expectedError: errors.New("limit offset must be integer"), }, - { // 12. Throw error when limit is not a valid integer + { + name: "12. Throw error when limit is not a valid integer", preset: false, presetValues: nil, command: []string{"ZRANGE", "ZrangeKey12", "a", "h", "BYLEX", "WITHSCORES", "LIMIT", "4", "limit"}, expectedResponse: [][]string{}, expectedError: errors.New("limit count must be integer"), }, - { // 13. Throw error when offset is negative + { + name: "13. Throw error when offset is negative", preset: false, presetValues: nil, command: []string{"ZRANGE", "ZrangeKey13", "a", "h", "BYLEX", "WITHSCORES", "LIMIT", "-4", "9"}, expectedResponse: [][]string{}, expectedError: errors.New("limit offset must be >= 0"), }, - { // 14. Throw error when the key does not hold a sorted set + { + name: "14. Throw error when the key does not hold a sorted set", preset: true, presetValues: map[string]interface{}{ "ZrangeKey14": "Default value", @@ -2769,14 +2957,16 @@ func Test_HandleZRANGE(t *testing.T) { expectedResponse: [][]string{}, expectedError: errors.New("value at ZrangeKey14 is not a sorted set"), }, - { // 15. Command too short + { + name: "15. Command too short", preset: false, presetValues: nil, command: []string{"ZRANGE", "ZrangeKey15", "1"}, expectedResponse: [][]string{}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 16 Command too long + { + name: "16 Command too long", preset: false, presetValues: nil, command: []string{"ZRANGE", "ZrangeKey16", "a", "h", "BYLEX", "WITHSCORES", "LIMIT", "-4", "9", "REV", "WITHSCORES"}, @@ -2786,58 +2976,61 @@ func Test_HandleZRANGE(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZRANGE, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZRANGE, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleZRANGE(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) + return } - } - res, err := handleZRANGE(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if len(rv.Array()) != len(test.expectedResponse) { - t.Errorf("expected response array of length %d, got %d", len(test.expectedResponse), len(rv.Array())) - } - for _, element := range rv.Array() { - if !slices.ContainsFunc(test.expectedResponse, func(expected []string) bool { - // The current sub-slice is a different length, return false because they're not equal - if len(element.Array()) != len(expected) { - return false - } - for i := 0; i < len(expected); i++ { - if element.Array()[i].String() != expected[i] { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) + } + if len(rv.Array()) != len(test.expectedResponse) { + t.Errorf("expected response array of length %d, got %d", len(test.expectedResponse), len(rv.Array())) + } + for _, element := range rv.Array() { + if !slices.ContainsFunc(test.expectedResponse, func(expected []string) bool { + // The current sub-slice is a different length, return false because they're not equal + if len(element.Array()) != len(expected) { return false } + for i := 0; i < len(expected); i++ { + if element.Array()[i].String() != expected[i] { + return false + } + } + return true + }) { + t.Errorf("expected response %+v, got %+v", test.expectedResponse, rv.Array()) } - return true - }) { - t.Errorf("expected response %+v, got %+v", test.expectedResponse, rv.Array()) } - } + }) } } func Test_HandleZRANGESTORE(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} destination string @@ -2846,7 +3039,8 @@ func Test_HandleZRANGESTORE(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Get elements withing score range without score. + { + name: "1. Get elements withing score range without score.", preset: true, presetValues: map[string]interface{}{ "ZrangeStoreKey1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2865,7 +3059,8 @@ func Test_HandleZRANGESTORE(t *testing.T) { }), expectedError: nil, }, - { // 2. Get elements within score range with score. + { + name: "2. Get elements within score range with score.", preset: true, presetValues: map[string]interface{}{ "ZrangeStoreKey2": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2884,8 +3079,10 @@ func Test_HandleZRANGESTORE(t *testing.T) { }), expectedError: nil, }, - { // 3. Get elements within score range with offset and limit. + { + // 3. Get elements within score range with offset and limit. // Offset and limit are in where we start and stop counting in the original sorted set (NOT THE RESULT). + name: "3. Get elements within score range with offset and limit.", preset: true, presetValues: map[string]interface{}{ "ZrangeStoreKey3": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2903,9 +3100,11 @@ func Test_HandleZRANGESTORE(t *testing.T) { }), expectedError: nil, }, - { // 4. Get elements within score range with offset and limit + reverse the results. + { + // 4. Get elements within score range with offset and limit + reverse the results. // Offset and limit are in where we start and stop counting in the original sorted set (NOT THE RESULT). // REV reverses the original set before getting the range. + name: "4. Get elements within score range with offset and limit + reverse the results.", preset: true, presetValues: map[string]interface{}{ "ZrangeStoreKey4": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2923,7 +3122,8 @@ func Test_HandleZRANGESTORE(t *testing.T) { }), expectedError: nil, }, - { // 5. Get elements within lex range without score. + { + name: "5. Get elements within lex range without score.", preset: true, presetValues: map[string]interface{}{ "ZrangeStoreKey5": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2942,7 +3142,8 @@ func Test_HandleZRANGESTORE(t *testing.T) { }), expectedError: nil, }, - { // 6. Get elements within lex range with score. + { + name: "6. Get elements within lex range with score.", preset: true, presetValues: map[string]interface{}{ "ZrangeStoreKey6": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2961,8 +3162,10 @@ func Test_HandleZRANGESTORE(t *testing.T) { }), expectedError: nil, }, - { // 7. Get elements within lex range with offset and limit. + { + // 7. Get elements within lex range with offset and limit. // Offset and limit are in where we start and stop counting in the original sorted set (NOT THE RESULT). + name: "7. Get elements within lex range with offset and limit.", preset: true, presetValues: map[string]interface{}{ "ZrangeStoreKey7": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -2980,9 +3183,11 @@ func Test_HandleZRANGESTORE(t *testing.T) { }), expectedError: nil, }, - { // 8. Get elements within lex range with offset and limit + reverse the results. + { + // 8. Get elements within lex range with offset and limit + reverse the results. // Offset and limit are in where we start and stop counting in the original sorted set (NOT THE RESULT). // REV reverses the original set before getting the range. + name: "8. Get elements within lex range with offset and limit + reverse the results.", preset: true, presetValues: map[string]interface{}{ "ZrangeStoreKey8": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3000,7 +3205,8 @@ func Test_HandleZRANGESTORE(t *testing.T) { }), expectedError: nil, }, - { // 9. Return an empty slice when we use BYLEX while elements have different scores + { + name: "9. Return an empty slice when we use BYLEX while elements have different scores", preset: true, presetValues: map[string]interface{}{ "ZrangeStoreKey9": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3016,35 +3222,40 @@ func Test_HandleZRANGESTORE(t *testing.T) { expectedValue: nil, expectedError: nil, }, - { // 10. Throw error when limit does not provide both offset and limit + { + name: "10. Throw error when limit does not provide both offset and limit", preset: false, presetValues: nil, command: []string{"ZRANGESTORE", "ZrangeStoreDestinationKey10", "ZrangeStoreKey10", "a", "h", "BYLEX", "WITHSCORES", "LIMIT", "2"}, expectedResponse: 0, expectedError: errors.New("limit should contain offset and count as integers"), }, - { // 11. Throw error when offset is not a valid integer + { + name: "11. Throw error when offset is not a valid integer", preset: false, presetValues: nil, command: []string{"ZRANGESTORE", "ZrangeStoreDestinationKey11", "ZrangeStoreKey11", "a", "h", "BYLEX", "WITHSCORES", "LIMIT", "offset", "4"}, expectedResponse: 0, expectedError: errors.New("limit offset must be integer"), }, - { // 12. Throw error when limit is not a valid integer + { + name: "12. Throw error when limit is not a valid integer", preset: false, presetValues: nil, command: []string{"ZRANGESTORE", "ZrangeStoreDestinationKey12", "ZrangeStoreKey12", "a", "h", "BYLEX", "WITHSCORES", "LIMIT", "4", "limit"}, expectedResponse: 0, expectedError: errors.New("limit count must be integer"), }, - { // 13. Throw error when offset is negative + { + name: "13. Throw error when offset is negative", preset: false, presetValues: nil, command: []string{"ZRANGESTORE", "ZrangeStoreDestinationKey13", "ZrangeStoreKey13", "a", "h", "BYLEX", "WITHSCORES", "LIMIT", "-4", "9"}, expectedResponse: 0, expectedError: errors.New("limit offset must be >= 0"), }, - { // 14. Throw error when the key does not hold a sorted set + { + name: "14. Throw error when the key does not hold a sorted set", preset: true, presetValues: map[string]interface{}{ "ZrangeStoreKey14": "Default value", @@ -3053,14 +3264,16 @@ func Test_HandleZRANGESTORE(t *testing.T) { expectedResponse: 0, expectedError: errors.New("value at ZrangeStoreKey14 is not a sorted set"), }, - { // 15. Command too short + { + name: "15. Command too short", preset: false, presetValues: nil, command: []string{"ZRANGESTORE", "ZrangeStoreKey15", "1"}, expectedResponse: 0, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 16 Command too long + { + name: "16 Command too long", preset: false, presetValues: nil, command: []string{"ZRANGESTORE", "ZrangeStoreDestinationKey16", "ZrangeStoreKey16", "a", "h", "BYLEX", "WITHSCORES", "LIMIT", "-4", "9", "REV", "WITHSCORES"}, @@ -3070,62 +3283,66 @@ func Test_HandleZRANGESTORE(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZRANGESTORE, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZRANGESTORE, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleZRANGESTORE(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) + return } - } - res, err := handleZRANGESTORE(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response integer %d, got %d", test.expectedResponse, rv.Integer()) - } - if test.expectedValue != nil { - if _, err = mockServer.KeyRLock(ctx, test.destination); err != nil { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - set, ok := mockServer.GetValue(ctx, test.destination).(*sorted_set.SortedSet) - if !ok { - t.Errorf("expected vaule at key %s to be set, got another type", test.destination) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response integer %d, got %d", test.expectedResponse, rv.Integer()) } - if !set.Equals(test.expectedValue) { - t.Errorf("expected sorted set %+v, got %+v", test.expectedValue, set) + if test.expectedValue != nil { + if _, err = mockServer.KeyRLock(ctx, test.destination); err != nil { + t.Error(err) + } + set, ok := mockServer.GetValue(ctx, test.destination).(*sorted_set.SortedSet) + if !ok { + t.Errorf("expected vaule at key %s to be set, got another type", test.destination) + } + if !set.Equals(test.expectedValue) { + t.Errorf("expected sorted set %+v, got %+v", test.expectedValue, set) + } + mockServer.KeyRUnlock(ctx, test.destination) } - mockServer.KeyRUnlock(ctx, test.destination) - } + }) } } func Test_HandleZINTER(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} command []string expectedResponse [][]string expectedError error }{ - { // 1. Get the intersection between 2 sorted sets. + { + name: "1. Get the intersection between 2 sorted sets.", preset: true, presetValues: map[string]interface{}{ "ZinterKey1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3146,6 +3363,7 @@ func Test_HandleZINTER(t *testing.T) { { // 2. Get the intersection between 3 sorted sets with scores. // By default, the SUM aggregate will be used. + name: "2. Get the intersection between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZinterKey3": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3172,6 +3390,7 @@ func Test_HandleZINTER(t *testing.T) { { // 3. Get the intersection between 3 sorted sets with scores. // Use MIN aggregate. + name: "3. Get the intersection between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZinterKey6": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3198,6 +3417,7 @@ func Test_HandleZINTER(t *testing.T) { { // 4. Get the intersection between 3 sorted sets with scores. // Use MAX aggregate. + name: "4. Get the intersection between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZinterKey9": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3224,6 +3444,7 @@ func Test_HandleZINTER(t *testing.T) { { // 5. Get the intersection between 3 sorted sets with scores. // Use SUM aggregate with weights modifier. + name: "5. Get the intersection between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZinterKey12": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3250,6 +3471,7 @@ func Test_HandleZINTER(t *testing.T) { { // 6. Get the intersection between 3 sorted sets with scores. // Use MAX aggregate with added weights. + name: "6. Get the intersection between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZinterKey15": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3276,6 +3498,7 @@ func Test_HandleZINTER(t *testing.T) { { // 7. Get the intersection between 3 sorted sets with scores. // Use MIN aggregate with added weights. + name: "7. Get the intersection between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZinterKey18": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3299,7 +3522,8 @@ func Test_HandleZINTER(t *testing.T) { expectedResponse: [][]string{{"one", "5"}, {"eight", "8"}}, expectedError: nil, }, - { // 8. Throw an error if there are more weights than keys + { + name: "8. Throw an error if there are more weights than keys", preset: true, presetValues: map[string]interface{}{ "ZinterKey21": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3314,7 +3538,8 @@ func Test_HandleZINTER(t *testing.T) { expectedResponse: nil, expectedError: errors.New("number of weights should match number of keys"), }, - { // 9. Throw an error if there are fewer weights than keys + { + name: "9. Throw an error if there are fewer weights than keys", preset: true, presetValues: map[string]interface{}{ "ZinterKey23": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3332,7 +3557,8 @@ func Test_HandleZINTER(t *testing.T) { expectedResponse: nil, expectedError: errors.New("number of weights should match number of keys"), }, - { // 10. Throw an error if there are no keys provided + { + name: "10. Throw an error if there are no keys provided", preset: true, presetValues: map[string]interface{}{ "ZinterKey26": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), @@ -3343,7 +3569,8 @@ func Test_HandleZINTER(t *testing.T) { expectedResponse: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 11. Throw an error if any of the provided keys are not sorted sets + { + name: "11. Throw an error if any of the provided keys are not sorted sets", preset: true, presetValues: map[string]interface{}{ "ZinterKey29": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3359,7 +3586,8 @@ func Test_HandleZINTER(t *testing.T) { expectedResponse: nil, expectedError: errors.New("value at ZinterKey30 is not a sorted set"), }, - { // 12. If any of the keys does not exist, return an empty array. + { + name: "12. If any of the keys does not exist, return an empty array.", preset: true, presetValues: map[string]interface{}{ "ZinterKey32": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3377,7 +3605,8 @@ func Test_HandleZINTER(t *testing.T) { expectedResponse: [][]string{}, expectedError: nil, }, - { // 13. Command too short + { + name: "13. Command too short", preset: false, command: []string{"ZINTER"}, expectedResponse: [][]string{}, @@ -3386,55 +3615,58 @@ func Test_HandleZINTER(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZINTER, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZINTER, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleZINTER(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) + return } - } - res, err := handleZINTER(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - for _, element := range rv.Array() { - if !slices.ContainsFunc(test.expectedResponse, func(expected []string) bool { - // The current sub-slice is a different length, return false because they're not equal - if len(element.Array()) != len(expected) { - return false - } - for i := 0; i < len(expected); i++ { - if element.Array()[i].String() != expected[i] { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) + } + for _, element := range rv.Array() { + if !slices.ContainsFunc(test.expectedResponse, func(expected []string) bool { + // The current sub-slice is a different length, return false because they're not equal + if len(element.Array()) != len(expected) { return false } + for i := 0; i < len(expected); i++ { + if element.Array()[i].String() != expected[i] { + return false + } + } + return true + }) { + t.Errorf("expected response %+v, got %+v", test.expectedResponse, rv.Array()) } - return true - }) { - t.Errorf("expected response %+v, got %+v", test.expectedResponse, rv.Array()) } - } + }) } } func Test_HandleZINTERSTORE(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} destination string @@ -3443,7 +3675,8 @@ func Test_HandleZINTERSTORE(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Get the intersection between 2 sorted sets. + { + name: "1. Get the intersection between 2 sorted sets.", preset: true, presetValues: map[string]interface{}{ "ZinterStoreKey1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3469,6 +3702,7 @@ func Test_HandleZINTERSTORE(t *testing.T) { { // 2. Get the intersection between 3 sorted sets with scores. // By default, the SUM aggregate will be used. + name: "2. Get the intersection between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZinterStoreKey3": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3499,6 +3733,7 @@ func Test_HandleZINTERSTORE(t *testing.T) { { // 3. Get the intersection between 3 sorted sets with scores. // Use MIN aggregate. + name: "3. Get the intersection between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZinterStoreKey6": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3529,6 +3764,7 @@ func Test_HandleZINTERSTORE(t *testing.T) { { // 4. Get the intersection between 3 sorted sets with scores. // Use MAX aggregate. + name: "4. Get the intersection between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZinterStoreKey9": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3559,6 +3795,7 @@ func Test_HandleZINTERSTORE(t *testing.T) { { // 5. Get the intersection between 3 sorted sets with scores. // Use SUM aggregate with weights modifier. + name: "5. Get the intersection between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZinterStoreKey12": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3589,6 +3826,7 @@ func Test_HandleZINTERSTORE(t *testing.T) { { // 6. Get the intersection between 3 sorted sets with scores. // Use MAX aggregate with added weights. + name: "6. Get the intersection between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZinterStoreKey15": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3619,6 +3857,7 @@ func Test_HandleZINTERSTORE(t *testing.T) { { // 7. Get the intersection between 3 sorted sets with scores. // Use MIN aggregate with added weights. + name: "7. Get the intersection between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZinterStoreKey18": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3646,7 +3885,8 @@ func Test_HandleZINTERSTORE(t *testing.T) { expectedResponse: 2, expectedError: nil, }, - { // 8. Throw an error if there are more weights than keys + { + name: "8. Throw an error if there are more weights than keys", preset: true, presetValues: map[string]interface{}{ "ZinterStoreKey21": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3661,7 +3901,8 @@ func Test_HandleZINTERSTORE(t *testing.T) { expectedResponse: 0, expectedError: errors.New("number of weights should match number of keys"), }, - { // 9. Throw an error if there are fewer weights than keys + { + name: "9. Throw an error if there are fewer weights than keys", preset: true, presetValues: map[string]interface{}{ "ZinterStoreKey23": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3679,7 +3920,8 @@ func Test_HandleZINTERSTORE(t *testing.T) { expectedResponse: 0, expectedError: errors.New("number of weights should match number of keys"), }, - { // 10. Throw an error if there are no keys provided + { + name: "10. Throw an error if there are no keys provided", preset: true, presetValues: map[string]interface{}{ "ZinterStoreKey26": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), @@ -3690,7 +3932,8 @@ func Test_HandleZINTERSTORE(t *testing.T) { expectedResponse: 0, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 11. Throw an error if any of the provided keys are not sorted sets + { + name: "11. Throw an error if any of the provided keys are not sorted sets", preset: true, presetValues: map[string]interface{}{ "ZinterStoreKey29": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3706,7 +3949,8 @@ func Test_HandleZINTERSTORE(t *testing.T) { expectedResponse: 0, expectedError: errors.New("value at ZinterStoreKey30 is not a sorted set"), }, - { // 12. If any of the keys does not exist, return an empty array. + { + name: "12. If any of the keys does not exist, return an empty array.", preset: true, presetValues: map[string]interface{}{ "ZinterStoreKey32": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3724,7 +3968,8 @@ func Test_HandleZINTERSTORE(t *testing.T) { expectedResponse: 0, expectedError: nil, }, - { // 13. Command too short + { + name: "13. Command too short", preset: false, command: []string{"ZINTERSTORE"}, expectedResponse: 0, @@ -3733,64 +3978,68 @@ func Test_HandleZINTERSTORE(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZINTERSTORE, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZINTERSTORE, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleZINTERSTORE(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) + return } - } - res, err := handleZINTERSTORE(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response integer %d, got %d", test.expectedResponse, rv.Integer()) - } - if test.expectedValue != nil { - if _, err = mockServer.KeyRLock(ctx, test.destination); err != nil { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - set, ok := mockServer.GetValue(ctx, test.destination).(*sorted_set.SortedSet) - if !ok { - t.Errorf("expected vaule at key %s to be set, got another type", test.destination) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response integer %d, got %d", test.expectedResponse, rv.Integer()) } - for _, elem := range set.GetAll() { - if !test.expectedValue.Contains(elem.Value) { - t.Errorf("could not find element %s in the expected values", elem.Value) + if test.expectedValue != nil { + if _, err = mockServer.KeyRLock(ctx, test.destination); err != nil { + t.Error(err) + } + set, ok := mockServer.GetValue(ctx, test.destination).(*sorted_set.SortedSet) + if !ok { + t.Errorf("expected vaule at key %s to be set, got another type", test.destination) + } + for _, elem := range set.GetAll() { + if !test.expectedValue.Contains(elem.Value) { + t.Errorf("could not find element %s in the expected values", elem.Value) + } } + mockServer.KeyRUnlock(ctx, test.destination) } - mockServer.KeyRUnlock(ctx, test.destination) - } + }) } } func Test_HandleZUNION(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} command []string expectedResponse [][]string expectedError error }{ - { // 1. Get the union between 2 sorted sets. + { + name: "1. Get the union between 2 sorted sets.", preset: true, presetValues: map[string]interface{}{ "ZunionKey1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3811,6 +4060,7 @@ func Test_HandleZUNION(t *testing.T) { { // 2. Get the union between 3 sorted sets with scores. // By default, the SUM aggregate will be used. + name: "2. Get the union between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZunionKey3": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3841,6 +4091,7 @@ func Test_HandleZUNION(t *testing.T) { { // 3. Get the union between 3 sorted sets with scores. // Use MIN aggregate. + name: "3. Get the union between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZunionKey6": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3871,6 +4122,7 @@ func Test_HandleZUNION(t *testing.T) { { // 4. Get the union between 3 sorted sets with scores. // Use MAX aggregate. + name: "4. Get the union between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZunionKey9": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3901,6 +4153,7 @@ func Test_HandleZUNION(t *testing.T) { { // 5. Get the union between 3 sorted sets with scores. // Use SUM aggregate with weights modifier. + name: "5. Get the union between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZunionKey12": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3931,6 +4184,7 @@ func Test_HandleZUNION(t *testing.T) { { // 6. Get the union between 3 sorted sets with scores. // Use MAX aggregate with added weights. + name: "6. Get the union between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZunionKey15": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3961,6 +4215,7 @@ func Test_HandleZUNION(t *testing.T) { { // 7. Get the union between 3 sorted sets with scores. // Use MIN aggregate with added weights. + name: "7. Get the union between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZunionKey18": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -3987,7 +4242,8 @@ func Test_HandleZUNION(t *testing.T) { }, expectedError: nil, }, - { // 8. Throw an error if there are more weights than keys + { + name: "8. Throw an error if there are more weights than keys", preset: true, presetValues: map[string]interface{}{ "ZunionKey21": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -4002,7 +4258,8 @@ func Test_HandleZUNION(t *testing.T) { expectedResponse: nil, expectedError: errors.New("number of weights should match number of keys"), }, - { // 9. Throw an error if there are fewer weights than keys + { + name: "9. Throw an error if there are fewer weights than keys", preset: true, presetValues: map[string]interface{}{ "ZunionKey23": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -4020,7 +4277,8 @@ func Test_HandleZUNION(t *testing.T) { expectedResponse: nil, expectedError: errors.New("number of weights should match number of keys"), }, - { // 10. Throw an error if there are no keys provided + { + name: "10. Throw an error if there are no keys provided", preset: true, presetValues: map[string]interface{}{ "ZunionKey26": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), @@ -4031,7 +4289,8 @@ func Test_HandleZUNION(t *testing.T) { expectedResponse: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 11. Throw an error if any of the provided keys are not sorted sets + { + name: "11. Throw an error if any of the provided keys are not sorted sets", preset: true, presetValues: map[string]interface{}{ "ZunionKey29": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -4047,7 +4306,8 @@ func Test_HandleZUNION(t *testing.T) { expectedResponse: nil, expectedError: errors.New("value at ZunionKey30 is not a sorted set"), }, - { // 12. If any of the keys does not exist, skip it. + { + name: "12. If any of the keys does not exist, skip it.", preset: true, presetValues: map[string]interface{}{ "ZunionKey32": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -4068,7 +4328,8 @@ func Test_HandleZUNION(t *testing.T) { }, expectedError: nil, }, - { // 13. Command too short + { + name: "13. Command too short", preset: false, command: []string{"ZUNION"}, expectedError: errors.New(constants.WrongArgsResponse), @@ -4076,55 +4337,58 @@ func Test_HandleZUNION(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZUNION, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZUNION, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleZUNION(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) + return } - } - res, err := handleZUNION(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - for _, element := range rv.Array() { - if !slices.ContainsFunc(test.expectedResponse, func(expected []string) bool { - // The current sub-slice is a different length, return false because they're not equal - if len(element.Array()) != len(expected) { - return false - } - for i := 0; i < len(expected); i++ { - if element.Array()[i].String() != expected[i] { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) + } + for _, element := range rv.Array() { + if !slices.ContainsFunc(test.expectedResponse, func(expected []string) bool { + // The current sub-slice is a different length, return false because they're not equal + if len(element.Array()) != len(expected) { return false } + for i := 0; i < len(expected); i++ { + if element.Array()[i].String() != expected[i] { + return false + } + } + return true + }) { + t.Errorf("expected response %+v, got %+v", test.expectedResponse, rv.Array()) } - return true - }) { - t.Errorf("expected response %+v, got %+v", test.expectedResponse, rv.Array()) } - } + }) } } func Test_HandleZUNIONSTORE(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} destination string @@ -4133,7 +4397,8 @@ func Test_HandleZUNIONSTORE(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Get the union between 2 sorted sets. + { + name: "1. Get the union between 2 sorted sets.", preset: true, presetValues: map[string]interface{}{ "ZunionStoreKey1": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -4161,6 +4426,7 @@ func Test_HandleZUNIONSTORE(t *testing.T) { { // 2. Get the union between 3 sorted sets with scores. // By default, the SUM aggregate will be used. + name: "2. Get the union between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZunionStoreKey3": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -4194,6 +4460,7 @@ func Test_HandleZUNIONSTORE(t *testing.T) { { // 3. Get the union between 3 sorted sets with scores. // Use MIN aggregate. + name: "3. Get the union between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZunionStoreKey6": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -4227,6 +4494,7 @@ func Test_HandleZUNIONSTORE(t *testing.T) { { // 4. Get the union between 3 sorted sets with scores. // Use MAX aggregate. + name: "4. Get the union between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZunionStoreKey9": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -4262,6 +4530,7 @@ func Test_HandleZUNIONSTORE(t *testing.T) { { // 5. Get the union between 3 sorted sets with scores. // Use SUM aggregate with weights modifier. + name: "5. Get the union between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZunionStoreKey12": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -4298,6 +4567,7 @@ func Test_HandleZUNIONSTORE(t *testing.T) { { // 6. Get the union between 3 sorted sets with scores. // Use MAX aggregate with added weights. + name: "6. Get the union between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZunionStoreKey15": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -4333,6 +4603,7 @@ func Test_HandleZUNIONSTORE(t *testing.T) { { // 7. Get the union between 3 sorted sets with scores. // Use MIN aggregate with added weights. + name: "7. Get the union between 3 sorted sets with scores.", preset: true, presetValues: map[string]interface{}{ "ZunionStoreKey18": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -4366,7 +4637,8 @@ func Test_HandleZUNIONSTORE(t *testing.T) { expectedResponse: 13, expectedError: nil, }, - { // 8. Throw an error if there are more weights than keys + { + name: "8. Throw an error if there are more weights than keys", preset: true, presetValues: map[string]interface{}{ "ZunionStoreKey21": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -4382,7 +4654,8 @@ func Test_HandleZUNIONSTORE(t *testing.T) { expectedResponse: 0, expectedError: errors.New("number of weights should match number of keys"), }, - { // 9. Throw an error if there are fewer weights than keys + { + name: "9. Throw an error if there are fewer weights than keys", preset: true, presetValues: map[string]interface{}{ "ZunionStoreKey23": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -4401,7 +4674,8 @@ func Test_HandleZUNIONSTORE(t *testing.T) { expectedResponse: 0, expectedError: errors.New("number of weights should match number of keys"), }, - { // 10. Throw an error if there are no keys provided + { + name: "10. Throw an error if there are no keys provided", preset: true, presetValues: map[string]interface{}{ "ZunionStoreKey26": sorted_set.NewSortedSet([]sorted_set.MemberParam{{Value: "one", Score: 1}}), @@ -4412,7 +4686,8 @@ func Test_HandleZUNIONSTORE(t *testing.T) { expectedResponse: 0, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 11. Throw an error if any of the provided keys are not sorted sets + { + name: "11. Throw an error if any of the provided keys are not sorted sets", preset: true, presetValues: map[string]interface{}{ "ZunionStoreKey29": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -4429,7 +4704,8 @@ func Test_HandleZUNIONSTORE(t *testing.T) { expectedResponse: 0, expectedError: errors.New("value at ZunionStoreKey30 is not a sorted set"), }, - { // 12. If any of the keys does not exist, skip it. + { + name: "12. If any of the keys does not exist, skip it.", preset: true, presetValues: map[string]interface{}{ "ZunionStoreKey32": sorted_set.NewSortedSet([]sorted_set.MemberParam{ @@ -4453,7 +4729,8 @@ func Test_HandleZUNIONSTORE(t *testing.T) { expectedResponse: 9, expectedError: nil, }, - { // 13. Command too short + { + name: "13. Command too short", preset: false, command: []string{"ZUNIONSTORE"}, expectedResponse: 0, @@ -4462,51 +4739,53 @@ func Test_HandleZUNIONSTORE(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZUNIONSTORE, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZUNIONSTORE, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleZUNIONSTORE(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) + return } - } - res, err := handleZUNIONSTORE(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response integer %d, got %d", test.expectedResponse, rv.Integer()) - } - if test.expectedValue != nil { - if _, err = mockServer.KeyRLock(ctx, test.destination); err != nil { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - set, ok := mockServer.GetValue(ctx, test.destination).(*sorted_set.SortedSet) - if !ok { - t.Errorf("expected vaule at key %s to be set, got another type", test.destination) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response integer %d, got %d", test.expectedResponse, rv.Integer()) } - for _, elem := range set.GetAll() { - if !test.expectedValue.Contains(elem.Value) { - t.Errorf("could not find element %s in the expected values", elem.Value) + if test.expectedValue != nil { + if _, err = mockServer.KeyRLock(ctx, test.destination); err != nil { + t.Error(err) + } + set, ok := mockServer.GetValue(ctx, test.destination).(*sorted_set.SortedSet) + if !ok { + t.Errorf("expected vaule at key %s to be set, got another type", test.destination) + } + for _, elem := range set.GetAll() { + if !test.expectedValue.Contains(elem.Value) { + t.Errorf("could not find element %s in the expected values", elem.Value) + } } + mockServer.KeyRUnlock(ctx, test.destination) } - mockServer.KeyRUnlock(ctx, test.destination) - } + }) } } From 16743a36df13975966f8f59aa2cb239f700942dd Mon Sep 17 00:00:00 2001 From: Kelvin Mwinuka Date: Sat, 6 Apr 2024 02:21:29 +0800 Subject: [PATCH 5/8] Implemented t.Run in generic, hash, list, and set module tests --- coverage/coverage.out | 692 ++++++------- internal/clock/clock.go | 2 +- pkg/modules/generic/commands_test.go | 1088 +++++++++++--------- pkg/modules/hash/commands_test.go | 992 ++++++++++-------- pkg/modules/list/commands_test.go | 935 +++++++++-------- pkg/modules/set/commant_test.go | 1405 ++++++++++++++------------ 6 files changed, 2783 insertions(+), 2331 deletions(-) diff --git a/coverage/coverage.out b/coverage/coverage.out index a293d55e..203fd0b9 100644 --- a/coverage/coverage.out +++ b/coverage/coverage.out @@ -1108,270 +1108,88 @@ github.com/echovault/echovault/pkg/modules/acl/commands.go:578.62,580.7 1 1 github.com/echovault/echovault/pkg/modules/acl/commands.go:589.62,591.7 1 1 github.com/echovault/echovault/pkg/modules/acl/commands.go:603.62,605.7 1 0 github.com/echovault/echovault/pkg/modules/acl/commands.go:614.62,616.7 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:31.105,33.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:33.16,35.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:37.2,40.25 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:40.25,42.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:44.2,44.38 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:44.38,46.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:48.2,48.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:48.33,50.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:50.17,52.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:53.3,54.59 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:54.59,56.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:57.3,57.59 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:60.2,60.51 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:60.51,62.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:63.2,66.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:66.9,68.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:70.2,71.36 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:71.36,72.42 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:72.42,73.26 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:73.26,76.5 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:77.4,77.12 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:79.3,80.13 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:82.2,82.55 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:82.55,84.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:86.2,86.51 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:89.105,91.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:91.16,93.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:95.2,98.33 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:98.33,100.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:102.2,102.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:102.52,104.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:105.2,108.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:108.9,110.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:112.2,115.31 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:115.31,117.19 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:117.19,119.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:121.3,121.34 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:121.34,123.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:125.3,125.31 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:125.31,127.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:129.3,129.35 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:129.35,132.12 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:134.3,134.32 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:137.2,137.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:140.108,142.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:142.16,144.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:146.2,149.33 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:149.33,151.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:153.2,153.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:153.52,155.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:156.2,159.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:159.9,161.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:163.2,166.31 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:166.31,168.19 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:168.19,170.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:172.3,172.34 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:172.34,174.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:176.3,176.35 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:176.35,179.12 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:181.3,181.31 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:181.31,183.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:185.3,185.18 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:188.2,188.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:191.106,193.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:193.16,195.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:197.2,199.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:199.33,201.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:203.2,203.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:203.52,205.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:206.2,209.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:209.9,211.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:213.2,214.27 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:214.27,215.32 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:215.32,217.12 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:219.3,219.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:219.33,222.12 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:224.3,224.29 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:224.29,226.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:229.2,229.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:232.111,234.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:234.16,236.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:238.2,241.19 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:241.19,243.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:243.17,245.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:246.3,246.13 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:246.13,248.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:249.3,249.12 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:252.2,253.19 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:253.19,254.46 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:254.46,256.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:256.9,258.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:261.2,261.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:261.33,263.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:265.2,265.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:265.52,267.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:268.2,271.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:271.9,273.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:276.2,276.24 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:276.24,278.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:278.17,280.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:281.3,281.34 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:281.34,283.18 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:283.18,284.36 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:284.36,286.14 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:288.5,288.37 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:288.37,291.14 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:293.5,293.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:293.33,295.14 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:299.3,299.26 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:303.2,304.29 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:304.29,306.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:309.2,311.46 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:311.46,315.16 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:315.16,316.59 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:316.59,318.5 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:322.2,323.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:323.16,325.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:326.2,326.38 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:326.38,328.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:328.17,329.41 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:329.41,331.13 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:333.4,333.42 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:333.42,336.13 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:338.4,338.38 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:338.38,340.13 2 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:345.2,345.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:348.105,350.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:350.16,352.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:354.2,356.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:356.33,358.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:360.2,360.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:360.52,362.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:363.2,366.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:366.9,368.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:370.2,370.55 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:373.106,375.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:375.16,377.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:379.2,381.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:381.33,383.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:385.2,385.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:385.52,387.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:388.2,391.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:391.9,393.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:395.2,396.29 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:396.29,398.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:400.2,400.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:403.108,405.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:405.16,407.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:409.2,415.47 5 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:415.47,417.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:417.17,419.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:420.3,420.21 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:421.8,423.17 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:423.17,425.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:426.3,426.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:429.2,429.33 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:429.33,430.62 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:430.62,432.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:433.3,435.48 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:435.48,437.57 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:437.57,439.5 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:440.4,440.96 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:441.9,443.57 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:443.57,445.5 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:446.4,446.60 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:450.2,450.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:450.52,452.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:453.2,456.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:456.9,458.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:460.2,460.24 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:460.24,462.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:464.2,464.28 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:465.10,466.69 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:467.11,469.48 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:469.48,471.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:471.9,473.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:474.15,476.48 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:476.48,478.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:478.9,480.4 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:483.2,483.55 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:483.55,485.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:487.2,487.40 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:487.40,489.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:491.2,492.47 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:495.108,497.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:497.16,499.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:501.2,503.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:503.33,505.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:507.2,507.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:507.52,509.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:510.2,513.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:513.9,515.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:517.2,518.33 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:518.33,520.34 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:520.34,522.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:523.3,523.35 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:523.35,526.4 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:527.3,527.31 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:527.31,529.4 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:532.2,532.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:535.108,537.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:537.16,539.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:541.2,544.33 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:544.33,546.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:548.2,548.52 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:548.52,550.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:551.2,554.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:554.9,556.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:558.2,558.24 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:558.24,560.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:562.2,562.30 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:565.105,567.16 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:567.16,569.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:571.2,574.33 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:574.33,576.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:578.2,578.51 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:578.51,580.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:581.2,584.9 3 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:584.9,586.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:588.2,590.31 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:590.31,591.25 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:591.25,594.4 2 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:597.2,597.55 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:597.55,599.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/commands.go:601.2,601.51 1 1 -github.com/echovault/echovault/pkg/modules/hash/commands.go:604.33,725.2 1 0 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:22.50,23.18 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:23.18,25.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:26.2,26.22 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:29.52,30.18 1 0 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:30.18,32.3 1 0 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:33.2,33.22 1 0 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:36.50,37.18 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:37.18,39.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:40.2,40.22 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:43.53,44.18 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:44.18,46.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:47.2,47.22 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:50.51,51.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:51.19,53.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:54.2,54.21 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:57.56,58.34 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:58.34,60.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:61.2,61.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:61.19,63.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:64.2,64.22 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:67.50,68.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:68.19,70.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:71.2,71.21 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:74.51,75.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:75.19,77.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:78.2,78.21 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:81.53,82.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:82.19,84.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:85.2,85.22 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:88.53,89.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:89.19,91.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:92.2,92.21 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:95.53,96.19 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:96.19,98.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:99.2,99.22 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:102.50,103.18 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:103.18,105.3 1 1 -github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:106.2,106.22 1 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:29.115,35.29 4 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:35.29,36.54 1 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:36.54,42.42 4 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:42.42,44.5 1 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:46.4,49.12 3 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:52.3,52.36 1 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:52.36,59.43 5 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:59.43,61.5 1 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:63.4,65.21 2 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:69.2,71.25 2 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:74.109,78.35 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:78.35,79.65 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:79.65,80.41 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:80.41,82.5 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:83.4,83.12 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:85.3,85.13 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:88.2,88.51 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:91.110,92.18 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:93.9,98.36 4 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:98.36,99.66 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:99.66,100.52 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:100.52,104.6 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:105.5,105.13 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:107.4,108.14 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:110.3,111.26 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:113.9,117.45 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:117.45,119.4 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:120.3,120.42 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:120.42,124.37 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:124.37,125.67 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:125.67,126.53 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:126.53,127.59 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:127.59,131.8 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:133.6,133.14 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:135.5,135.54 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:135.54,138.6 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:140.9,140.50 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:140.50,144.37 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:144.37,145.67 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:145.67,146.53 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:146.53,148.24 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:148.24,151.8 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:153.6,153.14 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:155.5,155.33 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:155.33,158.6 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:160.9,160.49 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:160.49,164.37 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:164.37,165.67 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:165.67,166.53 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:166.53,167.55 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:167.55,171.8 3 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:173.6,173.14 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:175.5,175.50 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:175.50,178.6 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:180.9,182.4 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:183.3,184.26 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:185.10,186.54 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:190.103,192.2 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:194.33,202.60 1 1 +github.com/echovault/echovault/pkg/modules/admin/commands.go:202.60,202.86 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:211.60,213.5 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:221.62,221.88 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:230.62,230.88 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:240.62,240.88 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:251.60,253.5 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:254.113,255.49 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:255.49,257.6 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:258.5,258.45 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:267.60,269.5 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:270.113,272.18 2 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:272.18,274.6 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:275.5,275.53 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:284.60,286.5 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:287.113,288.47 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:288.47,290.6 1 0 +github.com/echovault/echovault/pkg/modules/admin/commands.go:291.5,291.45 1 0 +github.com/echovault/echovault/pkg/modules/connection/commands.go:26.108,27.18 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:28.10,29.54 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:30.9,31.34 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:32.9,33.72 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:37.33,45.60 1 0 +github.com/echovault/echovault/pkg/modules/connection/commands.go:45.60,47.5 1 0 github.com/echovault/echovault/pkg/modules/generic/commands.go:36.104,38.16 2 1 github.com/echovault/echovault/pkg/modules/generic/commands.go:38.16,40.3 1 1 github.com/echovault/echovault/pkg/modules/generic/commands.go:42.2,48.16 6 1 @@ -1622,88 +1440,270 @@ github.com/echovault/echovault/pkg/modules/generic/utils.go:107.3,109.17 3 1 github.com/echovault/echovault/pkg/modules/generic/utils.go:109.17,111.4 1 1 github.com/echovault/echovault/pkg/modules/generic/utils.go:112.3,113.53 2 1 github.com/echovault/echovault/pkg/modules/generic/utils.go:115.10,116.95 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:29.115,35.29 4 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:35.29,36.54 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:36.54,42.42 4 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:42.42,44.5 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:46.4,49.12 3 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:52.3,52.36 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:52.36,59.43 5 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:59.43,61.5 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:63.4,65.21 2 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:69.2,71.25 2 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:74.109,78.35 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:78.35,79.65 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:79.65,80.41 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:80.41,82.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:83.4,83.12 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:85.3,85.13 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:88.2,88.51 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:91.110,92.18 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:93.9,98.36 4 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:98.36,99.66 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:99.66,100.52 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:100.52,104.6 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:105.5,105.13 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:107.4,108.14 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:110.3,111.26 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:113.9,117.45 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:117.45,119.4 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:120.3,120.42 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:120.42,124.37 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:124.37,125.67 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:125.67,126.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:126.53,127.59 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:127.59,131.8 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:133.6,133.14 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:135.5,135.54 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:135.54,138.6 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:140.9,140.50 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:140.50,144.37 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:144.37,145.67 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:145.67,146.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:146.53,148.24 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:148.24,151.8 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:153.6,153.14 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:155.5,155.33 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:155.33,158.6 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:160.9,160.49 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:160.49,164.37 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:164.37,165.67 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:165.67,166.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:166.53,167.55 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:167.55,171.8 3 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:173.6,173.14 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:175.5,175.50 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:175.50,178.6 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:180.9,182.4 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:183.3,184.26 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:185.10,186.54 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:190.103,192.2 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:194.33,202.60 1 1 -github.com/echovault/echovault/pkg/modules/admin/commands.go:202.60,202.86 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:211.60,213.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:221.62,221.88 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:230.62,230.88 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:240.62,240.88 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:251.60,253.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:254.113,255.49 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:255.49,257.6 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:258.5,258.45 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:267.60,269.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:270.113,272.18 2 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:272.18,274.6 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:275.5,275.53 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:284.60,286.5 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:287.113,288.47 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:288.47,290.6 1 0 -github.com/echovault/echovault/pkg/modules/admin/commands.go:291.5,291.45 1 0 -github.com/echovault/echovault/pkg/modules/connection/commands.go:26.108,27.18 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:28.10,29.54 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:30.9,31.34 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:32.9,33.72 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:37.33,45.60 1 0 -github.com/echovault/echovault/pkg/modules/connection/commands.go:45.60,47.5 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:31.105,33.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:33.16,35.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:37.2,40.25 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:40.25,42.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:44.2,44.38 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:44.38,46.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:48.2,48.33 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:48.33,50.17 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:50.17,52.4 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:53.3,54.59 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:54.59,56.4 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:57.3,57.59 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:60.2,60.51 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:60.51,62.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:63.2,66.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:66.9,68.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:70.2,71.36 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:71.36,72.42 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:72.42,73.26 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:73.26,76.5 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:77.4,77.12 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:79.3,80.13 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:82.2,82.55 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:82.55,84.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:86.2,86.51 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:89.105,91.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:91.16,93.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:95.2,98.33 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:98.33,100.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:102.2,102.52 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:102.52,104.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:105.2,108.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:108.9,110.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:112.2,115.31 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:115.31,117.19 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:117.19,119.12 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:121.3,121.34 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:121.34,123.12 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:125.3,125.31 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:125.31,127.12 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:129.3,129.35 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:129.35,132.12 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:134.3,134.32 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:137.2,137.25 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:140.108,142.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:142.16,144.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:146.2,149.33 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:149.33,151.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:153.2,153.52 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:153.52,155.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:156.2,159.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:159.9,161.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:163.2,166.31 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:166.31,168.19 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:168.19,170.12 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:172.3,172.34 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:172.34,174.12 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:176.3,176.35 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:176.35,179.12 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:181.3,181.31 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:181.31,183.12 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:185.3,185.18 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:188.2,188.25 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:191.106,193.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:193.16,195.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:197.2,199.33 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:199.33,201.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:203.2,203.52 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:203.52,205.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:206.2,209.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:209.9,211.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:213.2,214.27 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:214.27,215.32 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:215.32,217.12 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:219.3,219.33 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:219.33,222.12 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:224.3,224.29 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:224.29,226.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:229.2,229.25 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:232.111,234.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:234.16,236.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:238.2,241.19 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:241.19,243.17 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:243.17,245.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:246.3,246.13 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:246.13,248.4 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:249.3,249.12 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:252.2,253.19 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:253.19,254.46 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:254.46,256.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:256.9,258.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:261.2,261.33 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:261.33,263.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:265.2,265.52 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:265.52,267.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:268.2,271.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:271.9,273.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:276.2,276.24 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:276.24,278.17 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:278.17,280.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:281.3,281.34 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:281.34,283.18 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:283.18,284.36 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:284.36,286.14 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:288.5,288.37 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:288.37,291.14 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:293.5,293.33 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:293.33,295.14 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:299.3,299.26 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:303.2,304.29 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:304.29,306.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:309.2,311.46 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:311.46,315.16 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:315.16,316.59 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:316.59,318.5 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:322.2,323.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:323.16,325.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:326.2,326.38 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:326.38,328.17 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:328.17,329.41 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:329.41,331.13 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:333.4,333.42 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:333.42,336.13 3 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:338.4,338.38 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:338.38,340.13 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:345.2,345.25 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:348.105,350.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:350.16,352.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:354.2,356.33 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:356.33,358.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:360.2,360.52 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:360.52,362.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:363.2,366.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:366.9,368.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:370.2,370.55 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:373.106,375.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:375.16,377.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:379.2,381.33 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:381.33,383.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:385.2,385.52 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:385.52,387.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:388.2,391.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:391.9,393.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:395.2,396.29 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:396.29,398.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:400.2,400.25 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:403.108,405.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:405.16,407.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:409.2,415.47 5 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:415.47,417.17 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:417.17,419.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:420.3,420.21 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:421.8,423.17 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:423.17,425.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:426.3,426.19 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:429.2,429.33 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:429.33,430.62 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:430.62,432.4 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:433.3,435.48 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:435.48,437.57 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:437.57,439.5 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:440.4,440.96 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:441.9,443.57 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:443.57,445.5 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:446.4,446.60 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:450.2,450.52 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:450.52,452.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:453.2,456.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:456.9,458.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:460.2,460.24 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:460.24,462.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:464.2,464.28 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:465.10,466.69 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:467.11,469.48 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:469.48,471.4 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:471.9,473.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:474.15,476.48 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:476.48,478.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:478.9,480.4 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:483.2,483.55 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:483.55,485.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:487.2,487.40 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:487.40,489.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:491.2,492.47 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:495.108,497.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:497.16,499.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:501.2,503.33 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:503.33,505.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:507.2,507.52 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:507.52,509.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:510.2,513.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:513.9,515.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:517.2,518.33 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:518.33,520.34 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:520.34,522.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:523.3,523.35 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:523.35,526.4 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:527.3,527.31 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:527.31,529.4 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:532.2,532.25 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:535.108,537.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:537.16,539.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:541.2,544.33 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:544.33,546.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:548.2,548.52 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:548.52,550.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:551.2,554.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:554.9,556.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:558.2,558.24 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:558.24,560.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:562.2,562.30 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:565.105,567.16 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:567.16,569.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:571.2,574.33 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:574.33,576.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:578.2,578.51 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:578.51,580.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:581.2,584.9 3 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:584.9,586.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:588.2,590.31 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:590.31,591.25 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:591.25,594.4 2 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:597.2,597.55 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:597.55,599.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/commands.go:601.2,601.51 1 1 +github.com/echovault/echovault/pkg/modules/hash/commands.go:604.33,725.2 1 0 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:22.50,23.18 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:23.18,25.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:26.2,26.22 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:29.52,30.18 1 0 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:30.18,32.3 1 0 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:33.2,33.22 1 0 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:36.50,37.18 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:37.18,39.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:40.2,40.22 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:43.53,44.18 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:44.18,46.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:47.2,47.22 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:50.51,51.19 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:51.19,53.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:54.2,54.21 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:57.56,58.34 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:58.34,60.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:61.2,61.19 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:61.19,63.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:64.2,64.22 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:67.50,68.19 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:68.19,70.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:71.2,71.21 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:74.51,75.19 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:75.19,77.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:78.2,78.21 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:81.53,82.19 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:82.19,84.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:85.2,85.22 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:88.53,89.19 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:89.19,91.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:92.2,92.21 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:95.53,96.19 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:96.19,98.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:99.2,99.22 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:102.50,103.18 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:103.18,105.3 1 1 +github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:106.2,106.22 1 1 github.com/echovault/echovault/pkg/modules/list/commands.go:30.105,32.16 2 1 github.com/echovault/echovault/pkg/modules/list/commands.go:32.16,34.3 1 1 github.com/echovault/echovault/pkg/modules/list/commands.go:36.2,38.33 2 1 diff --git a/internal/clock/clock.go b/internal/clock/clock.go index 036a06a7..70133de2 100644 --- a/internal/clock/clock.go +++ b/internal/clock/clock.go @@ -32,7 +32,7 @@ func (RealClock) After(d time.Duration) <-chan time.Time { type MockClock struct{} func (MockClock) Now() time.Time { - t, _ := time.Parse(time.RFC3339, "2036-01-02T15:04:05+07:00") + t, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05+07:00") return t } diff --git a/pkg/modules/generic/commands_test.go b/pkg/modules/generic/commands_test.go index 2fa51682..fd64081a 100644 --- a/pkg/modules/generic/commands_test.go +++ b/pkg/modules/generic/commands_test.go @@ -50,6 +50,7 @@ func init() { func Test_HandleSET(t *testing.T) { tests := []struct { + name string command []string presetValues map[string]KeyData expectedResponse interface{} @@ -57,7 +58,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry time.Time expectedErr error }{ - { // 1. Set normal string value + { + name: "1. Set normal string value", command: []string{"SET", "SetKey1", "value1"}, presetValues: nil, expectedResponse: "OK", @@ -65,7 +67,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: nil, }, - { // 2. Set normal integer value + { + name: "2. Set normal integer value", command: []string{"SET", "SetKey2", "1245678910"}, presetValues: nil, expectedResponse: "OK", @@ -73,7 +76,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: nil, }, - { // 3. Set normal float value + { + name: "3. Set normal float value", command: []string{"SET", "SetKey3", "45782.11341"}, presetValues: nil, expectedResponse: "OK", @@ -81,7 +85,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: nil, }, - { // 4. Only set the value if the key does not exist + { + name: "4. Only set the value if the key does not exist", command: []string{"SET", "SetKey4", "value4", "NX"}, presetValues: nil, expectedResponse: "OK", @@ -89,7 +94,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: nil, }, - { // 5. Throw error when value already exists with NX flag passed + { + name: "5. Throw error when value already exists with NX flag passed", command: []string{"SET", "SetKey5", "value5", "NX"}, presetValues: map[string]KeyData{ "SetKey5": { @@ -102,7 +108,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: errors.New("key SetKey5 already exists"), }, - { // 6. Set new key value when key exists with XX flag passed + { + name: "6. Set new key value when key exists with XX flag passed", command: []string{"SET", "SetKey6", "value6", "XX"}, presetValues: map[string]KeyData{ "SetKey6": { @@ -115,7 +122,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: nil, }, - { // 7. Return error when setting non-existent key with XX flag + { + name: "7. Return error when setting non-existent key with XX flag", command: []string{"SET", "SetKey7", "value7", "XX"}, presetValues: nil, expectedResponse: nil, @@ -123,7 +131,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: errors.New("key SetKey7 does not exist"), }, - { // 8. Return error when NX flag is provided after XX flag + { + name: "8. Return error when NX flag is provided after XX flag", command: []string{"SET", "SetKey8", "value8", "XX", "NX"}, presetValues: nil, expectedResponse: nil, @@ -131,7 +140,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: errors.New("cannot specify NX when XX is already specified"), }, - { // 9. Return error when XX flag is provided after NX flag + { + name: "9. Return error when XX flag is provided after NX flag", command: []string{"SET", "SetKey9", "value9", "NX", "XX"}, presetValues: nil, expectedResponse: nil, @@ -139,7 +149,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: errors.New("cannot specify XX when NX is already specified"), }, - { // 10. Set expiry time on the key to 100 seconds from now + { + name: "10. Set expiry time on the key to 100 seconds from now", command: []string{"SET", "SetKey10", "value10", "EX", "100"}, presetValues: nil, expectedResponse: "OK", @@ -147,7 +158,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: mockClock.Now().Add(100 * time.Second), expectedErr: nil, }, - { // 11. Return error when EX flag is passed without seconds value + { + name: "11. Return error when EX flag is passed without seconds value", command: []string{"SET", "SetKey11", "value11", "EX"}, presetValues: nil, expectedResponse: nil, @@ -155,7 +167,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: errors.New("seconds value required after EX"), }, - { // 12. Return error when EX flag is passed with invalid (non-integer) value + { + name: "12. Return error when EX flag is passed with invalid (non-integer) value", command: []string{"SET", "SetKey12", "value12", "EX", "seconds"}, presetValues: nil, expectedResponse: nil, @@ -163,7 +176,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: errors.New("seconds value should be an integer"), }, - { // 13. Return error when trying to set expiry seconds when expiry is already set + { + name: "13. Return error when trying to set expiry seconds when expiry is already set", command: []string{"SET", "SetKey13", "value13", "PX", "100000", "EX", "100"}, presetValues: nil, expectedResponse: nil, @@ -171,7 +185,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: errors.New("cannot specify EX when expiry time is already set"), }, - { // 14. Set expiry time on the key in unix milliseconds + { + name: "14. Set expiry time on the key in unix milliseconds", command: []string{"SET", "SetKey14", "value14", "PX", "4096"}, presetValues: nil, expectedResponse: "OK", @@ -179,7 +194,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: mockClock.Now().Add(4096 * time.Millisecond), expectedErr: nil, }, - { // 15. Return error when PX flag is passed without milliseconds value + { + name: "15. Return error when PX flag is passed without milliseconds value", command: []string{"SET", "SetKey15", "value15", "PX"}, presetValues: nil, expectedResponse: nil, @@ -187,7 +203,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: errors.New("milliseconds value required after PX"), }, - { // 16. Return error when PX flag is passed with invalid (non-integer) value + { + name: "16. Return error when PX flag is passed with invalid (non-integer) value", command: []string{"SET", "SetKey16", "value16", "PX", "milliseconds"}, presetValues: nil, expectedResponse: nil, @@ -195,7 +212,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: errors.New("milliseconds value should be an integer"), }, - { // 17. Return error when trying to set expiry milliseconds when expiry is already provided + { + name: "17. Return error when trying to set expiry milliseconds when expiry is already provided", command: []string{"SET", "SetKey17", "value17", "EX", "10", "PX", "1000000"}, presetValues: nil, expectedResponse: nil, @@ -203,7 +221,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: errors.New("cannot specify PX when expiry time is already set"), }, - { // 18. Set exact expiry time in seconds from unix epoch + { + name: "18. Set exact expiry time in seconds from unix epoch", command: []string{ "SET", "SetKey18", "value18", "EXAT", fmt.Sprintf("%d", mockClock.Now().Add(200*time.Second).Unix()), @@ -214,7 +233,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: mockClock.Now().Add(200 * time.Second), expectedErr: nil, }, - { // 19. Return error when trying to set exact seconds expiry time when expiry time is already provided + { + name: "19. Return error when trying to set exact seconds expiry time when expiry time is already provided", command: []string{ "SET", "SetKey19", "value19", "EX", "10", @@ -226,7 +246,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: errors.New("cannot specify EXAT when expiry time is already set"), }, - { // 20. Return error when no seconds value is provided after EXAT flag + { + name: "20. Return error when no seconds value is provided after EXAT flag", command: []string{"SET", "SetKey20", "value20", "EXAT"}, presetValues: nil, expectedResponse: nil, @@ -234,7 +255,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: errors.New("seconds value required after EXAT"), }, - { // 21. Return error when invalid (non-integer) value is passed after EXAT flag + { + name: "21. Return error when invalid (non-integer) value is passed after EXAT flag", command: []string{"SET", "SekKey21", "value21", "EXAT", "seconds"}, presetValues: nil, expectedResponse: nil, @@ -242,7 +264,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: errors.New("seconds value should be an integer"), }, - { // 22. Set exact expiry time in milliseconds from unix epoch + { + name: "22. Set exact expiry time in milliseconds from unix epoch", command: []string{ "SET", "SetKey22", "value22", "PXAT", fmt.Sprintf("%d", mockClock.Now().Add(4096*time.Millisecond).UnixMilli()), @@ -253,7 +276,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: mockClock.Now().Add(4096 * time.Millisecond), expectedErr: nil, }, - { // 23. Return error when trying to set exact milliseconds expiry time when expiry time is already provided + { + name: "23. Return error when trying to set exact milliseconds expiry time when expiry time is already provided", command: []string{ "SET", "SetKey23", "value23", "PX", "1000", @@ -265,7 +289,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: errors.New("cannot specify PXAT when expiry time is already set"), }, - { // 24. Return error when no milliseconds value is provided after PXAT flag + { + name: "24. Return error when no milliseconds value is provided after PXAT flag", command: []string{"SET", "SetKey24", "value24", "PXAT"}, presetValues: nil, expectedResponse: nil, @@ -273,7 +298,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: errors.New("milliseconds value required after PXAT"), }, - { // 25. Return error when invalid (non-integer) value is passed after EXAT flag + { + name: "25. Return error when invalid (non-integer) value is passed after EXAT flag", command: []string{"SET", "SetKey25", "value25", "PXAT", "unix-milliseconds"}, presetValues: nil, expectedResponse: nil, @@ -281,7 +307,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: errors.New("milliseconds value should be an integer"), }, - { // 26. Get the previous value when GET flag is passed + { + name: "26. Get the previous value when GET flag is passed", command: []string{"SET", "SetKey26", "value26", "GET", "EX", "1000"}, presetValues: map[string]KeyData{ "SetKey26": { @@ -294,7 +321,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: mockClock.Now().Add(1000 * time.Second), expectedErr: nil, }, - { // 27. Return nil when GET value is passed and no previous value exists + { + name: "27. Return nil when GET value is passed and no previous value exists", command: []string{"SET", "SetKey27", "value27", "GET", "EX", "1000"}, presetValues: nil, expectedResponse: nil, @@ -302,7 +330,8 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: mockClock.Now().Add(1000 * time.Second), expectedErr: nil, }, - { // 28. Throw error when unknown optional flag is passed to SET command. + { + name: "28. Throw error when unknown optional flag is passed to SET command.", command: []string{"SET", "SetKey28", "value28", "UNKNOWN-OPTION"}, presetValues: nil, expectedResponse: nil, @@ -310,13 +339,15 @@ func Test_HandleSET(t *testing.T) { expectedExpiry: time.Time{}, expectedErr: errors.New("unknown option UNKNOWN-OPTION for set command"), }, - { // 29. Command too short + { + name: "29. Command too short", command: []string{"SET"}, expectedResponse: nil, expectedValue: nil, expectedErr: errors.New(constants.WrongArgsResponse), }, - { // 30. Command too long + { + name: "30. Command too long", command: []string{"SET", "SetKey30", "value1", "value2", "value3", "value4", "value5", "value6"}, expectedResponse: nil, expectedValue: nil, @@ -325,89 +356,94 @@ func Test_HandleSET(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SET, %d", i+1)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SET, %d", i+1)) + + if test.presetValues != nil { + for k, v := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, k); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, k, v.Value); err != nil { + t.Error(err) + } + mockServer.SetExpiry(ctx, k, v.ExpireAt, false) + mockServer.KeyUnlock(ctx, k) + } + } - if test.presetValues != nil { - for k, v := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, k); err != nil { - t.Error(err) + res, err := handleSet(ctx, test.command, mockServer, nil) + if test.expectedErr != nil { + if err == nil { + t.Errorf("expected error \"%s\", got nil", test.expectedErr.Error()) } - if err := mockServer.SetValue(ctx, k, v.Value); err != nil { - t.Error(err) + if test.expectedErr.Error() != err.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedErr.Error(), err.Error()) } - mockServer.SetExpiry(ctx, k, v.ExpireAt, false) - mockServer.KeyUnlock(ctx, k) + return + } + if err != nil { + t.Error(err) } - } - res, err := handleSet(ctx, test.command, mockServer, nil) - if test.expectedErr != nil { - if err == nil { - t.Errorf("expected error \"%s\", got nil", test.expectedErr.Error()) + rd := resp.NewReader(bytes.NewReader(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - if test.expectedErr.Error() != err.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedErr.Error(), err.Error()) + + switch test.expectedResponse.(type) { + case string: + if test.expectedResponse != rv.String() { + t.Errorf("expected response \"%s\", got \"%s\"", test.expectedResponse, rv.String()) + } + case nil: + if !rv.IsNull() { + t.Errorf("expcted nil response, got %+v", rv) + } + default: + t.Error("test expected result should be nil or string") } - continue - } - if err != nil { - t.Error(err) - } - - rd := resp.NewReader(bytes.NewReader(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - - switch test.expectedResponse.(type) { - case string: - if test.expectedResponse != rv.String() { - t.Errorf("expected response \"%s\", got \"%s\"", test.expectedResponse, rv.String()) + + // Compare expected value and expected time + key := test.command[1] + var value interface{} + var expireAt time.Time + + if _, err = mockServer.KeyLock(ctx, key); err != nil { + t.Error(err) } - case nil: - if !rv.IsNull() { - t.Errorf("expcted nil response, got %+v", rv) + value = mockServer.GetValue(ctx, key) + expireAt = mockServer.GetExpiry(ctx, key) + mockServer.KeyUnlock(ctx, key) + + if value != test.expectedValue { + t.Errorf("expected value %+v, got %+v", test.expectedValue, value) + } + if test.expectedExpiry.Unix() != expireAt.Unix() { + t.Errorf("expected expiry time %d, got %d, cmd: %+v", test.expectedExpiry.Unix(), expireAt.Unix(), test.command) } - default: - t.Error("test expected result should be nil or string") - } - - // Compare expected value and expected time - key := test.command[1] - var value interface{} - var expireAt time.Time - - if _, err = mockServer.KeyLock(ctx, key); err != nil { - t.Error(err) - } - value = mockServer.GetValue(ctx, key) - expireAt = mockServer.GetExpiry(ctx, key) - mockServer.KeyUnlock(ctx, key) - - if value != test.expectedValue { - t.Errorf("expected value %+v, got %+v", test.expectedValue, value) - } - if test.expectedExpiry.Unix() != expireAt.Unix() { - t.Errorf("expected expiry time %d, got %d, cmd: %+v", test.expectedExpiry.Unix(), expireAt.Unix(), test.command) - } + }) } } func Test_HandleMSET(t *testing.T) { tests := []struct { + name string command []string expectedResponse string expectedValues map[string]interface{} expectedErr error }{ { + name: "1. Set multiple key value pairs", command: []string{"MSET", "MsetKey1", "value1", "MsetKey2", "10", "MsetKey3", "3.142"}, expectedResponse: "OK", expectedValues: map[string]interface{}{"MsetKey1": "value1", "MsetKey2": 10, "MsetKey3": 3.142}, expectedErr: nil, }, { + name: "2. Return error when keys and values are not even", command: []string{"MSET", "MsetKey1", "value1", "MsetKey2", "10", "MsetKey3"}, expectedResponse: "", expectedValues: make(map[string]interface{}), @@ -416,102 +452,110 @@ func Test_HandleMSET(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("MSET, %d", i)) - res, err := handleMSet(ctx, test.command, mockServer, nil) - if test.expectedErr != nil { - if err.Error() != test.expectedErr.Error() { - t.Errorf("expected error %s, got %s", test.expectedErr.Error(), err.Error()) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("MSET, %d", i)) + res, err := handleMSet(ctx, test.command, mockServer, nil) + if test.expectedErr != nil { + if err.Error() != test.expectedErr.Error() { + t.Errorf("expected error %s, got %s", test.expectedErr.Error(), err.Error()) + } + return } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.String() != test.expectedResponse { - t.Errorf("expected response %s, got %s", test.expectedResponse, rv.String()) - } - for key, expectedValue := range test.expectedValues { - if _, err = mockServer.KeyRLock(ctx, key); err != nil { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - switch expectedValue.(type) { - default: - t.Error("unexpected type for expectedValue") - case int: - ev, _ := expectedValue.(int) - value, ok := mockServer.GetValue(ctx, key).(int) - if !ok { - t.Errorf("expected integer type for key %s, got another type", key) - } - if value != ev { - t.Errorf("expected value %d for key %s, got %d", ev, key, value) - } - case float64: - ev, _ := expectedValue.(float64) - value, ok := mockServer.GetValue(ctx, key).(float64) - if !ok { - t.Errorf("expected float type for key %s, got another type", key) - } - if value != ev { - t.Errorf("expected value %f for key %s, got %f", ev, key, value) - } - case string: - ev, _ := expectedValue.(string) - value, ok := mockServer.GetValue(ctx, key).(string) - if !ok { - t.Errorf("expected string type for key %s, got another type", key) + if rv.String() != test.expectedResponse { + t.Errorf("expected response %s, got %s", test.expectedResponse, rv.String()) + } + for key, expectedValue := range test.expectedValues { + if _, err = mockServer.KeyRLock(ctx, key); err != nil { + t.Error(err) } - if value != ev { - t.Errorf("expected value %s for key %s, got %s", ev, key, value) + switch expectedValue.(type) { + default: + t.Error("unexpected type for expectedValue") + case int: + ev, _ := expectedValue.(int) + value, ok := mockServer.GetValue(ctx, key).(int) + if !ok { + t.Errorf("expected integer type for key %s, got another type", key) + } + if value != ev { + t.Errorf("expected value %d for key %s, got %d", ev, key, value) + } + case float64: + ev, _ := expectedValue.(float64) + value, ok := mockServer.GetValue(ctx, key).(float64) + if !ok { + t.Errorf("expected float type for key %s, got another type", key) + } + if value != ev { + t.Errorf("expected value %f for key %s, got %f", ev, key, value) + } + case string: + ev, _ := expectedValue.(string) + value, ok := mockServer.GetValue(ctx, key).(string) + if !ok { + t.Errorf("expected string type for key %s, got another type", key) + } + if value != ev { + t.Errorf("expected value %s for key %s, got %s", ev, key, value) + } } + mockServer.KeyRUnlock(ctx, key) } - mockServer.KeyRUnlock(ctx, key) - } + }) } } func Test_HandleGET(t *testing.T) { tests := []struct { + name string key string value string }{ { + name: "1. String", key: "GetKey1", value: "value1", }, { + name: "2. Integer", key: "GetKey2", value: "10", }, { + name: "3. Float", key: "GetKey3", value: "3.142", }, } // Test successful GET command for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("GET, %d", i)) - func(key, value string) { + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("GET, %d", i)) + func(key, value string) { - _, err := mockServer.CreateKeyAndLock(ctx, key) - if err != nil { - t.Error(err) - } - if err = mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) - } - mockServer.KeyUnlock(ctx, key) + _, err := mockServer.CreateKeyAndLock(ctx, key) + if err != nil { + t.Error(err) + } + if err = mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) - res, err := handleGet(ctx, []string{"GET", key}, mockServer, nil) - if err != nil { - t.Error(err) - } - if !bytes.Equal(res, []byte(fmt.Sprintf("+%v\r\n", value))) { - t.Errorf("expected %s, got: %s", fmt.Sprintf("+%v\r\n", value), string(res)) - } - }(test.key, test.value) + res, err := handleGet(ctx, []string{"GET", key}, mockServer, nil) + if err != nil { + t.Error(err) + } + if !bytes.Equal(res, []byte(fmt.Sprintf("+%v\r\n", value))) { + t.Errorf("expected %s, got: %s", fmt.Sprintf("+%v\r\n", value), string(res)) + } + }(test.key, test.value) + }) } // Test get non-existent key @@ -524,31 +568,37 @@ func Test_HandleGET(t *testing.T) { } errorTests := []struct { + name string command []string expected string }{ { + name: "1. Return error when no GET key is passed", command: []string{"GET"}, expected: constants.WrongArgsResponse, }, { + name: "2. Return error when too many GET keys are passed", command: []string{"GET", "GetKey1", "test"}, expected: constants.WrongArgsResponse, }, } for _, test := range errorTests { - res, err = handleGet(context.Background(), test.command, mockServer, nil) - if res != nil { - t.Errorf("expected nil response, got: %+v", res) - } - if err.Error() != test.expected { - t.Errorf("expected error '%s', got: %s", test.expected, err.Error()) - } + t.Run(test.name, func(t *testing.T) { + res, err = handleGet(context.Background(), test.command, mockServer, nil) + if res != nil { + t.Errorf("expected nil response, got: %+v", res) + } + if err.Error() != test.expected { + t.Errorf("expected error '%s', got: %s", test.expected, err.Error()) + } + }) } } func Test_HandleMGET(t *testing.T) { tests := []struct { + name string presetKeys []string presetValues []string command []string @@ -556,6 +606,7 @@ func Test_HandleMGET(t *testing.T) { expectedError error }{ { + name: "1. MGET multiple existing values", presetKeys: []string{"MgetKey1", "MgetKey2", "MgetKey3", "MgetKey4"}, presetValues: []string{"value1", "value2", "value3", "value4"}, command: []string{"MGET", "MgetKey1", "MgetKey4", "MgetKey2", "MgetKey3", "MgetKey1"}, @@ -563,6 +614,7 @@ func Test_HandleMGET(t *testing.T) { expectedError: nil, }, { + name: "2. MGET multiple values with nil values spliced in", presetKeys: []string{"MgetKey5", "MgetKey6", "MgetKey7"}, presetValues: []string{"value5", "value6", "value7"}, command: []string{"MGET", "MgetKey5", "MgetKey6", "non-existent", "non-existent", "MgetKey7", "non-existent"}, @@ -570,6 +622,7 @@ func Test_HandleMGET(t *testing.T) { expectedError: nil, }, { + name: "3. Return error when MGET is invoked with no keys", presetKeys: []string{"MgetKey5"}, presetValues: []string{"value5"}, command: []string{"MGET"}, @@ -579,53 +632,56 @@ func Test_HandleMGET(t *testing.T) { } for _, test := range tests { - // Set up the values - for i, key := range test.presetKeys { - _, err := mockServer.CreateKeyAndLock(context.Background(), key) + t.Run(test.name, func(t *testing.T) { + // Set up the values + for i, key := range test.presetKeys { + _, err := mockServer.CreateKeyAndLock(context.Background(), key) + if err != nil { + t.Error(err) + } + if err = mockServer.SetValue(context.Background(), key, test.presetValues[i]); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(context.Background(), key) + } + // Test the command and its results + res, err := handleMGet(context.Background(), test.command, mockServer, nil) + if test.expectedError != nil { + // If we expect and error, branch out and check error + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error %+v, got: %+v", test.expectedError, err) + } + return + } if err != nil { t.Error(err) } - if err = mockServer.SetValue(context.Background(), key, test.presetValues[i]); err != nil { + rr := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rr.ReadValue() + if err != nil { t.Error(err) } - mockServer.KeyUnlock(context.Background(), key) - } - // Test the command and its results - res, err := handleMGet(context.Background(), test.command, mockServer, nil) - if test.expectedError != nil { - // If we expect and error, branch out and check error - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error %+v, got: %+v", test.expectedError, err) + if rv.Type().String() != "Array" { + t.Errorf("expected type Array, got: %s", rv.Type().String()) } - continue - } - if err != nil { - t.Error(err) - } - rr := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rr.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Type().String() != "Array" { - t.Errorf("expected type Array, got: %s", rv.Type().String()) - } - for i, value := range rv.Array() { - if test.expected[i] == nil { - if !value.IsNull() { - t.Errorf("expected nil value, got %+v", value) + for i, value := range rv.Array() { + if test.expected[i] == nil { + if !value.IsNull() { + t.Errorf("expected nil value, got %+v", value) + } + continue + } + if value.String() != test.expected[i] { + t.Errorf("expected value %s, got: %s", test.expected[i], value.String()) } - continue - } - if value.String() != test.expected[i] { - t.Errorf("expected value %s, got: %s", test.expected[i], value.String()) } - } + }) } } func Test_HandleDEL(t *testing.T) { tests := []struct { + name string command []string presetValues map[string]KeyData expectedResponse int @@ -633,6 +689,7 @@ func Test_HandleDEL(t *testing.T) { expectedErr error }{ { + name: "1. Delete multiple keys", command: []string{"DEL", "DelKey1", "DelKey2", "DelKey3", "DelKey4", "DelKey5"}, presetValues: map[string]KeyData{ "DelKey1": {Value: "value1", ExpireAt: time.Time{}}, @@ -651,6 +708,7 @@ func Test_HandleDEL(t *testing.T) { expectedErr: nil, }, { + name: "2. Return error when DEL is called with no keys", command: []string{"DEL"}, presetValues: nil, expectedResponse: 0, @@ -660,63 +718,67 @@ func Test_HandleDEL(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("DEL, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("DEL, %d", i)) + + if test.presetValues != nil { + for k, v := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, k); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, k, v.Value); err != nil { + t.Error(err) + } + mockServer.SetExpiry(ctx, k, v.ExpireAt, false) + mockServer.KeyUnlock(ctx, k) + } + } - if test.presetValues != nil { - for k, v := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, k); err != nil { - t.Error(err) + res, err := handleDel(ctx, test.command, mockServer, nil) + if test.expectedErr != nil { + if err == nil { + t.Errorf("exected error \"%s\", got nil", test.expectedErr.Error()) } - if err := mockServer.SetValue(ctx, k, v.Value); err != nil { - t.Error(err) + if test.expectedErr.Error() != err.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedErr.Error(), err.Error()) } - mockServer.SetExpiry(ctx, k, v.ExpireAt, false) - mockServer.KeyUnlock(ctx, k) + return + } + if err != nil { + t.Error(err) } - } - res, err := handleDel(ctx, test.command, mockServer, nil) - if test.expectedErr != nil { - if err == nil { - t.Errorf("exected error \"%s\", got nil", test.expectedErr.Error()) + rd := resp.NewReader(bytes.NewReader(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - if test.expectedErr.Error() != err.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedErr.Error(), err.Error()) + + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) } - continue - } - if err != nil { - t.Error(err) - } - - rd := resp.NewReader(bytes.NewReader(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) - } - - for k, expected := range test.expectToExist { - exists := mockServer.KeyExists(ctx, k) - if exists != expected { - t.Errorf("expected exists status to be %+v, got %+v", expected, exists) + + for k, expected := range test.expectToExist { + exists := mockServer.KeyExists(ctx, k) + if exists != expected { + t.Errorf("expected exists status to be %+v, got %+v", expected, exists) + } } - } + }) } } func Test_HandlePERSIST(t *testing.T) { tests := []struct { + name string command []string presetValues map[string]KeyData expectedResponse int expectedValues map[string]KeyData expectedError error }{ - { // 1. Successfully persist a volatile key + { + name: "1. Successfully persist a volatile key", command: []string{"PERSIST", "PersistKey1"}, presetValues: map[string]KeyData{ "PersistKey1": {Value: "value1", ExpireAt: mockClock.Now().Add(1000 * time.Second)}, @@ -727,14 +789,16 @@ func Test_HandlePERSIST(t *testing.T) { }, expectedError: nil, }, - { // 2. Return 0 when trying to persist a non-existent key + { + name: "2. Return 0 when trying to persist a non-existent key", command: []string{"PERSIST", "PersistKey2"}, presetValues: nil, expectedResponse: 0, expectedValues: nil, expectedError: nil, }, - { // 3. Return 0 when trying to persist a non-volatile key + { + name: "3. Return 0 when trying to persist a non-volatile key", command: []string{"PERSIST", "PersistKey3"}, presetValues: map[string]KeyData{ "PersistKey3": {Value: "value3", ExpireAt: time.Time{}}, @@ -745,14 +809,16 @@ func Test_HandlePERSIST(t *testing.T) { }, expectedError: nil, }, - { // 4. Command too short + { + name: "4. Command too short", command: []string{"PERSIST"}, presetValues: nil, expectedResponse: 0, expectedValues: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 5. Command too long + { + name: "5. Command too long", command: []string{"PERSIST", "PersistKey5", "key6"}, presetValues: nil, expectedResponse: 0, @@ -762,74 +828,78 @@ func Test_HandlePERSIST(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("PERSIST, %d", i)) - - if test.presetValues != nil { - for k, v := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, k); err != nil { - t.Error(err) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("PERSIST, %d", i)) + + if test.presetValues != nil { + for k, v := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, k); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, k, v.Value); err != nil { + t.Error(err) + } + mockServer.SetExpiry(ctx, k, v.ExpireAt, false) + mockServer.KeyUnlock(ctx, k) } - if err := mockServer.SetValue(ctx, k, v.Value); err != nil { - t.Error(err) - } - mockServer.SetExpiry(ctx, k, v.ExpireAt, false) - mockServer.KeyUnlock(ctx, k) } - } - res, err := handlePersist(ctx, test.command, mockServer, nil) + res, err := handlePersist(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err == nil { - t.Errorf("expected error \"%s\", got nil", test.expectedError.Error()) + if test.expectedError != nil { + if err == nil { + t.Errorf("expected error \"%s\", got nil", test.expectedError.Error()) + } + if test.expectedError.Error() != err.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return } - if test.expectedError.Error() != err.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - - rd := resp.NewReader(bytes.NewReader(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) - } - - if test.expectedValues == nil { - continue - } - - for k, expected := range test.expectedValues { - if _, err = mockServer.KeyLock(ctx, k); err != nil { + + rd := resp.NewReader(bytes.NewReader(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - value := mockServer.GetValue(ctx, k) - expiry := mockServer.GetExpiry(ctx, k) - if value != expected.Value { - t.Errorf("expected value %+v, got %+v", expected.Value, value) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) } - if expiry.UnixMilli() != expected.ExpireAt.UnixMilli() { - t.Errorf("expected exiry %d, got %d", expected.ExpireAt.UnixMilli(), expiry.UnixMilli()) + + if test.expectedValues == nil { + return } - mockServer.KeyUnlock(ctx, k) - } + + for k, expected := range test.expectedValues { + if _, err = mockServer.KeyLock(ctx, k); err != nil { + t.Error(err) + } + value := mockServer.GetValue(ctx, k) + expiry := mockServer.GetExpiry(ctx, k) + if value != expected.Value { + t.Errorf("expected value %+v, got %+v", expected.Value, value) + } + if expiry.UnixMilli() != expected.ExpireAt.UnixMilli() { + t.Errorf("expected exiry %d, got %d", expected.ExpireAt.UnixMilli(), expiry.UnixMilli()) + } + mockServer.KeyUnlock(ctx, k) + } + }) } } func Test_HandleEXPIRETIME(t *testing.T) { tests := []struct { + name string command []string presetValues map[string]KeyData expectedResponse int expectedError error }{ - { // 1. Return expire time in seconds + { + name: "1. Return expire time in seconds", command: []string{"EXPIRETIME", "ExpireTimeKey1"}, presetValues: map[string]KeyData{ "ExpireTimeKey1": {Value: "value1", ExpireAt: mockClock.Now().Add(100 * time.Second)}, @@ -837,7 +907,8 @@ func Test_HandleEXPIRETIME(t *testing.T) { expectedResponse: int(mockClock.Now().Add(100 * time.Second).Unix()), expectedError: nil, }, - { // 2. Return expire time in milliseconds + { + name: "2. Return expire time in milliseconds", command: []string{"PEXPIRETIME", "ExpireTimeKey2"}, presetValues: map[string]KeyData{ "ExpireTimeKey2": {Value: "value2", ExpireAt: mockClock.Now().Add(4096 * time.Millisecond)}, @@ -845,7 +916,8 @@ func Test_HandleEXPIRETIME(t *testing.T) { expectedResponse: int(mockClock.Now().Add(4096 * time.Millisecond).UnixMilli()), expectedError: nil, }, - { // 3. If the key is non-volatile, return -1 + { + name: "3. If the key is non-volatile, return -1", command: []string{"PEXPIRETIME", "ExpireTimeKey3"}, presetValues: map[string]KeyData{ "ExpireTimeKey3": {Value: "value3", ExpireAt: time.Time{}}, @@ -853,19 +925,22 @@ func Test_HandleEXPIRETIME(t *testing.T) { expectedResponse: -1, expectedError: nil, }, - { // 4. If the key is non-existent return -2 + { + name: "4. If the key is non-existent return -2", command: []string{"PEXPIRETIME", "ExpireTimeKey4"}, presetValues: nil, expectedResponse: -2, expectedError: nil, }, - { // 5. Command too short + { + name: "5. Command too short", command: []string{"PEXPIRETIME"}, presetValues: nil, expectedResponse: 0, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 6. Command too long + { + name: "6. Command too long", command: []string{"PEXPIRETIME", "ExpireTimeKey5", "ExpireTimeKey6"}, presetValues: nil, expectedResponse: 0, @@ -874,55 +949,59 @@ func Test_HandleEXPIRETIME(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("EXPIRETIME/PEXPIRETIME, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("EXPIRETIME/PEXPIRETIME, %d", i)) + + if test.presetValues != nil { + for k, v := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, k); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, k, v.Value); err != nil { + t.Error(err) + } + mockServer.SetExpiry(ctx, k, v.ExpireAt, false) + mockServer.KeyUnlock(ctx, k) + } + } - if test.presetValues != nil { - for k, v := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, k); err != nil { - t.Error(err) + res, err := handleExpireTime(ctx, test.command, mockServer, nil) + + if test.expectedError != nil { + if err == nil { + t.Errorf("expected error \"%s\", got nil", test.expectedError.Error()) } - if err := mockServer.SetValue(ctx, k, v.Value); err != nil { - t.Error(err) + if test.expectedError.Error() != err.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.SetExpiry(ctx, k, v.ExpireAt, false) - mockServer.KeyUnlock(ctx, k) + return + } + if err != nil { + t.Error(err) } - } - - res, err := handleExpireTime(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err == nil { - t.Errorf("expected error \"%s\", got nil", test.expectedError.Error()) + rd := resp.NewReader(bytes.NewReader(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - if test.expectedError.Error() != err.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) } - continue - } - if err != nil { - t.Error(err) - } - - rd := resp.NewReader(bytes.NewReader(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) - } + }) } } func Test_HandleTTL(t *testing.T) { tests := []struct { + name string command []string presetValues map[string]KeyData expectedResponse int expectedError error }{ - { // 1. Return TTL time in seconds + { + name: "1. Return TTL time in seconds", command: []string{"TTL", "TTLKey1"}, presetValues: map[string]KeyData{ "TTLKey1": {Value: "value1", ExpireAt: mockClock.Now().Add(100 * time.Second)}, @@ -930,7 +1009,8 @@ func Test_HandleTTL(t *testing.T) { expectedResponse: 100, expectedError: nil, }, - { // 2. Return TTL time in milliseconds + { + name: "2. Return TTL time in milliseconds", command: []string{"PTTL", "TTLKey2"}, presetValues: map[string]KeyData{ "TTLKey2": {Value: "value2", ExpireAt: mockClock.Now().Add(4096 * time.Millisecond)}, @@ -938,7 +1018,8 @@ func Test_HandleTTL(t *testing.T) { expectedResponse: 4096, expectedError: nil, }, - { // 3. If the key is non-volatile, return -1 + { + name: "3. If the key is non-volatile, return -1", command: []string{"TTL", "TTLKey3"}, presetValues: map[string]KeyData{ "TTLKey3": {Value: "value3", ExpireAt: time.Time{}}, @@ -946,19 +1027,22 @@ func Test_HandleTTL(t *testing.T) { expectedResponse: -1, expectedError: nil, }, - { // 4. If the key is non-existent return -2 + { + name: "4. If the key is non-existent return -2", command: []string{"TTL", "TTLKey4"}, presetValues: nil, expectedResponse: -2, expectedError: nil, }, - { // 5. Command too short + { + name: "5. Command too short", command: []string{"TTL"}, presetValues: nil, expectedResponse: 0, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 6. Command too long + { + name: "6. Command too long", command: []string{"TTL", "TTLKey5", "TTLKey6"}, presetValues: nil, expectedResponse: 0, @@ -967,56 +1051,60 @@ func Test_HandleTTL(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("TTL/PTTL, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("TTL/PTTL, %d", i)) + + if test.presetValues != nil { + for k, v := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, k); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, k, v.Value); err != nil { + t.Error(err) + } + mockServer.SetExpiry(ctx, k, v.ExpireAt, false) + mockServer.KeyUnlock(ctx, k) + } + } - if test.presetValues != nil { - for k, v := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, k); err != nil { - t.Error(err) + res, err := handleTTL(ctx, test.command, mockServer, nil) + + if test.expectedError != nil { + if err == nil { + t.Errorf("expected error \"%s\", got nil", test.expectedError.Error()) } - if err := mockServer.SetValue(ctx, k, v.Value); err != nil { - t.Error(err) + if test.expectedError.Error() != err.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.SetExpiry(ctx, k, v.ExpireAt, false) - mockServer.KeyUnlock(ctx, k) + return + } + if err != nil { + t.Error(err) } - } - - res, err := handleTTL(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err == nil { - t.Errorf("expected error \"%s\", got nil", test.expectedError.Error()) + rd := resp.NewReader(bytes.NewReader(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - if test.expectedError.Error() != err.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) } - continue - } - if err != nil { - t.Error(err) - } - - rd := resp.NewReader(bytes.NewReader(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) - } + }) } } func Test_HandleEXPIRE(t *testing.T) { tests := []struct { + name string command []string presetValues map[string]KeyData expectedResponse int expectedValues map[string]KeyData expectedError error }{ - { // 1. Set new expire by seconds + { + name: "1. Set new expire by seconds", command: []string{"EXPIRE", "ExpireKey1", "100"}, presetValues: map[string]KeyData{ "ExpireKey1": {Value: "value1", ExpireAt: time.Time{}}, @@ -1027,7 +1115,8 @@ func Test_HandleEXPIRE(t *testing.T) { }, expectedError: nil, }, - { // 2. Set new expire by milliseconds + { + name: "2. Set new expire by milliseconds", command: []string{"PEXPIRE", "ExpireKey2", "1000"}, presetValues: map[string]KeyData{ "ExpireKey2": {Value: "value2", ExpireAt: time.Time{}}, @@ -1038,7 +1127,8 @@ func Test_HandleEXPIRE(t *testing.T) { }, expectedError: nil, }, - { // 3. Set new expire only when key does not have an expiry time with NX flag + { + name: "3. Set new expire only when key does not have an expiry time with NX flag", command: []string{"EXPIRE", "ExpireKey3", "1000", "NX"}, presetValues: map[string]KeyData{ "ExpireKey3": {Value: "value3", ExpireAt: time.Time{}}, @@ -1049,7 +1139,8 @@ func Test_HandleEXPIRE(t *testing.T) { }, expectedError: nil, }, - { // 4. Return 0, when NX flag is provided and key already has an expiry time + { + name: "4. Return 0, when NX flag is provided and key already has an expiry time", command: []string{"EXPIRE", "ExpireKey4", "1000", "NX"}, presetValues: map[string]KeyData{ "ExpireKey4": {Value: "value4", ExpireAt: mockClock.Now().Add(1000 * time.Second)}, @@ -1060,7 +1151,8 @@ func Test_HandleEXPIRE(t *testing.T) { }, expectedError: nil, }, - { // 5. Set new expire time from now key only when the key already has an expiry time with XX flag + { + name: "5. Set new expire time from now key only when the key already has an expiry time with XX flag", command: []string{"EXPIRE", "ExpireKey5", "1000", "XX"}, presetValues: map[string]KeyData{ "ExpireKey5": {Value: "value5", ExpireAt: mockClock.Now().Add(30 * time.Second)}, @@ -1071,7 +1163,8 @@ func Test_HandleEXPIRE(t *testing.T) { }, expectedError: nil, }, - { // 6. Return 0 when key does not have an expiry and the XX flag is provided + { + name: "6. Return 0 when key does not have an expiry and the XX flag is provided", command: []string{"EXPIRE", "ExpireKey6", "1000", "XX"}, presetValues: map[string]KeyData{ "ExpireKey6": {Value: "value6", ExpireAt: time.Time{}}, @@ -1082,7 +1175,8 @@ func Test_HandleEXPIRE(t *testing.T) { }, expectedError: nil, }, - { // 7. Set expiry time when the provided time is after the current expiry time when GT flag is provided + { + name: "7. Set expiry time when the provided time is after the current expiry time when GT flag is provided", command: []string{"EXPIRE", "ExpireKey7", "1000", "GT"}, presetValues: map[string]KeyData{ "ExpireKey7": {Value: "value7", ExpireAt: mockClock.Now().Add(30 * time.Second)}, @@ -1093,7 +1187,8 @@ func Test_HandleEXPIRE(t *testing.T) { }, expectedError: nil, }, - { // 8. Return 0 when GT flag is passed and current expiry time is greater than provided time + { + name: "8. Return 0 when GT flag is passed and current expiry time is greater than provided time", command: []string{"EXPIRE", "ExpireKey8", "1000", "GT"}, presetValues: map[string]KeyData{ "ExpireKey8": {Value: "value8", ExpireAt: mockClock.Now().Add(3000 * time.Second)}, @@ -1104,7 +1199,8 @@ func Test_HandleEXPIRE(t *testing.T) { }, expectedError: nil, }, - { // 9. Return 0 when GT flag is passed and key does not have an expiry time + { + name: "9. Return 0 when GT flag is passed and key does not have an expiry time", command: []string{"EXPIRE", "ExpireKey9", "1000", "GT"}, presetValues: map[string]KeyData{ "ExpireKey9": {Value: "value9", ExpireAt: time.Time{}}, @@ -1115,7 +1211,8 @@ func Test_HandleEXPIRE(t *testing.T) { }, expectedError: nil, }, - { // 10. Set expiry time when the provided time is before the current expiry time when LT flag is provided + { + name: "10. Set expiry time when the provided time is before the current expiry time when LT flag is provided", command: []string{"EXPIRE", "ExpireKey10", "1000", "LT"}, presetValues: map[string]KeyData{ "ExpireKey10": {Value: "value10", ExpireAt: mockClock.Now().Add(3000 * time.Second)}, @@ -1126,7 +1223,8 @@ func Test_HandleEXPIRE(t *testing.T) { }, expectedError: nil, }, - { // 11. Return 0 when LT flag is passed and current expiry time is less than provided time + { + name: "11. Return 0 when LT flag is passed and current expiry time is less than provided time", command: []string{"EXPIRE", "ExpireKey11", "5000", "LT"}, presetValues: map[string]KeyData{ "ExpireKey11": {Value: "value11", ExpireAt: mockClock.Now().Add(3000 * time.Second)}, @@ -1137,7 +1235,8 @@ func Test_HandleEXPIRE(t *testing.T) { }, expectedError: nil, }, - { // 12. Return 0 when LT flag is passed and key does not have an expiry time + { + name: "12. Return 0 when LT flag is passed and key does not have an expiry time", command: []string{"EXPIRE", "ExpireKey12", "1000", "LT"}, presetValues: map[string]KeyData{ "ExpireKey12": {Value: "value12", ExpireAt: time.Time{}}, @@ -1148,7 +1247,8 @@ func Test_HandleEXPIRE(t *testing.T) { }, expectedError: nil, }, - { // 13. Return error when unknown flag is passed + { + name: "13. Return error when unknown flag is passed", command: []string{"EXPIRE", "ExpireKey13", "1000", "UNKNOWN"}, presetValues: map[string]KeyData{ "ExpireKey13": {Value: "value13", ExpireAt: time.Time{}}, @@ -1157,21 +1257,24 @@ func Test_HandleEXPIRE(t *testing.T) { expectedValues: nil, expectedError: errors.New("unknown option UNKNOWN"), }, - { // 14. Return error when expire time is not a valid integer + { + name: "14. Return error when expire time is not a valid integer", command: []string{"EXPIRE", "ExpireKey14", "expire"}, presetValues: nil, expectedResponse: 0, expectedValues: nil, expectedError: errors.New("expire time must be integer"), }, - { // 15. Command too short + { + name: "15. Command too short", command: []string{"EXPIRE"}, presetValues: nil, expectedResponse: 0, expectedValues: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 16. Command too long + { + name: "16. Command too long", command: []string{"EXPIRE", "ExpireKey16", "10", "NX", "GT"}, presetValues: nil, expectedResponse: 0, @@ -1181,75 +1284,79 @@ func Test_HandleEXPIRE(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("PERSIST, %d", i)) - - if test.presetValues != nil { - for k, v := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, k); err != nil { - t.Error(err) - } - if err := mockServer.SetValue(ctx, k, v.Value); err != nil { - t.Error(err) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("PERSIST, %d", i)) + + if test.presetValues != nil { + for k, v := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, k); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, k, v.Value); err != nil { + t.Error(err) + } + mockServer.SetExpiry(ctx, k, v.ExpireAt, false) + mockServer.KeyUnlock(ctx, k) } - mockServer.SetExpiry(ctx, k, v.ExpireAt, false) - mockServer.KeyUnlock(ctx, k) } - } - res, err := handleExpire(ctx, test.command, mockServer, nil) + res, err := handleExpire(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err == nil { - t.Errorf("expected error \"%s\", got nil", test.expectedError.Error()) + if test.expectedError != nil { + if err == nil { + t.Errorf("expected error \"%s\", got nil", test.expectedError.Error()) + } + if test.expectedError.Error() != err.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return } - if test.expectedError.Error() != err.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - - rd := resp.NewReader(bytes.NewReader(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) - } - - if test.expectedValues == nil { - continue - } - - for k, expected := range test.expectedValues { - if _, err = mockServer.KeyLock(ctx, k); err != nil { + + rd := resp.NewReader(bytes.NewReader(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - value := mockServer.GetValue(ctx, k) - expiry := mockServer.GetExpiry(ctx, k) - if value != expected.Value { - t.Errorf("expected value %+v, got %+v", expected.Value, value) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) } - if expiry.UnixMilli() != expected.ExpireAt.UnixMilli() { - t.Errorf("expected expiry %d, got %d", expected.ExpireAt.UnixMilli(), expiry.UnixMilli()) + + if test.expectedValues == nil { + return + } + + for k, expected := range test.expectedValues { + if _, err = mockServer.KeyLock(ctx, k); err != nil { + t.Error(err) + } + value := mockServer.GetValue(ctx, k) + expiry := mockServer.GetExpiry(ctx, k) + if value != expected.Value { + t.Errorf("expected value %+v, got %+v", expected.Value, value) + } + if expiry.UnixMilli() != expected.ExpireAt.UnixMilli() { + t.Errorf("expected expiry %d, got %d", expected.ExpireAt.UnixMilli(), expiry.UnixMilli()) + } + mockServer.KeyUnlock(ctx, k) } - mockServer.KeyUnlock(ctx, k) - } + }) } } func Test_HandleEXPIREAT(t *testing.T) { tests := []struct { + name string command []string presetValues map[string]KeyData expectedResponse int expectedValues map[string]KeyData expectedError error }{ - { // 1. Set new expire by unix seconds + { + name: "1. Set new expire by unix seconds", command: []string{"EXPIREAT", "ExpireAtKey1", fmt.Sprintf("%d", mockClock.Now().Add(1000*time.Second).Unix())}, presetValues: map[string]KeyData{ "ExpireAtKey1": {Value: "value1", ExpireAt: time.Time{}}, @@ -1260,7 +1367,8 @@ func Test_HandleEXPIREAT(t *testing.T) { }, expectedError: nil, }, - { // 2. Set new expire by milliseconds + { + name: "2. Set new expire by milliseconds", command: []string{"PEXPIREAT", "ExpireAtKey2", fmt.Sprintf("%d", mockClock.Now().Add(1000*time.Second).UnixMilli())}, presetValues: map[string]KeyData{ "ExpireAtKey2": {Value: "value2", ExpireAt: time.Time{}}, @@ -1271,7 +1379,8 @@ func Test_HandleEXPIREAT(t *testing.T) { }, expectedError: nil, }, - { // 3. Set new expire only when key does not have an expiry time with NX flag + { + name: "3. Set new expire only when key does not have an expiry time with NX flag", command: []string{"EXPIREAT", "ExpireAtKey3", fmt.Sprintf("%d", mockClock.Now().Add(1000*time.Second).Unix()), "NX"}, presetValues: map[string]KeyData{ "ExpireAtKey3": {Value: "value3", ExpireAt: time.Time{}}, @@ -1282,7 +1391,8 @@ func Test_HandleEXPIREAT(t *testing.T) { }, expectedError: nil, }, - { // 4. Return 0, when NX flag is provided and key already has an expiry time + { + name: "4. Return 0, when NX flag is provided and key already has an expiry time", command: []string{"EXPIREAT", "ExpireAtKey4", fmt.Sprintf("%d", mockClock.Now().Add(1000*time.Second).Unix()), "NX"}, presetValues: map[string]KeyData{ "ExpireAtKey4": {Value: "value4", ExpireAt: mockClock.Now().Add(1000 * time.Second)}, @@ -1293,7 +1403,8 @@ func Test_HandleEXPIREAT(t *testing.T) { }, expectedError: nil, }, - { // 5. Set new expire time from now key only when the key already has an expiry time with XX flag + { + name: "5. Set new expire time from now key only when the key already has an expiry time with XX flag", command: []string{ "EXPIREAT", "ExpireAtKey5", fmt.Sprintf("%d", mockClock.Now().Add(1000*time.Second).Unix()), "XX", @@ -1307,7 +1418,8 @@ func Test_HandleEXPIREAT(t *testing.T) { }, expectedError: nil, }, - { // 6. Return 0 when key does not have an expiry and the XX flag is provided + { + name: "6. Return 0 when key does not have an expiry and the XX flag is provided", command: []string{ "EXPIREAT", "ExpireAtKey6", fmt.Sprintf("%d", mockClock.Now().Add(1000*time.Second).Unix()), "XX", @@ -1321,7 +1433,8 @@ func Test_HandleEXPIREAT(t *testing.T) { }, expectedError: nil, }, - { // 7. Set expiry time when the provided time is after the current expiry time when GT flag is provided + { + name: "7. Set expiry time when the provided time is after the current expiry time when GT flag is provided", command: []string{ "EXPIREAT", "ExpireAtKey7", fmt.Sprintf("%d", mockClock.Now().Add(1000*time.Second).Unix()), "GT", @@ -1335,7 +1448,8 @@ func Test_HandleEXPIREAT(t *testing.T) { }, expectedError: nil, }, - { // 8. Return 0 when GT flag is passed and current expiry time is greater than provided time + { + name: "8. Return 0 when GT flag is passed and current expiry time is greater than provided time", command: []string{ "EXPIREAT", "ExpireAtKey8", fmt.Sprintf("%d", mockClock.Now().Add(1000*time.Second).Unix()), "GT", @@ -1349,7 +1463,8 @@ func Test_HandleEXPIREAT(t *testing.T) { }, expectedError: nil, }, - { // 9. Return 0 when GT flag is passed and key does not have an expiry time + { + name: "9. Return 0 when GT flag is passed and key does not have an expiry time", command: []string{ "EXPIREAT", "ExpireAtKey9", fmt.Sprintf("%d", mockClock.Now().Add(1000*time.Second).Unix()), "GT", @@ -1363,7 +1478,8 @@ func Test_HandleEXPIREAT(t *testing.T) { }, expectedError: nil, }, - { // 10. Set expiry time when the provided time is before the current expiry time when LT flag is provided + { + name: "10. Set expiry time when the provided time is before the current expiry time when LT flag is provided", command: []string{ "EXPIREAT", "ExpireAtKey10", fmt.Sprintf("%d", mockClock.Now().Add(1000*time.Second).Unix()), "LT", @@ -1377,7 +1493,8 @@ func Test_HandleEXPIREAT(t *testing.T) { }, expectedError: nil, }, - { // 11. Return 0 when LT flag is passed and current expiry time is less than provided time + { + name: "11. Return 0 when LT flag is passed and current expiry time is less than provided time", command: []string{ "EXPIREAT", "ExpireAtKey11", fmt.Sprintf("%d", mockClock.Now().Add(3000*time.Second).Unix()), "LT", @@ -1391,7 +1508,8 @@ func Test_HandleEXPIREAT(t *testing.T) { }, expectedError: nil, }, - { // 12. Return 0 when LT flag is passed and key does not have an expiry time + { + name: "12. Return 0 when LT flag is passed and key does not have an expiry time", command: []string{ "EXPIREAT", "ExpireAtKey12", fmt.Sprintf("%d", mockClock.Now().Add(1000*time.Second).Unix()), "LT", @@ -1405,7 +1523,8 @@ func Test_HandleEXPIREAT(t *testing.T) { }, expectedError: nil, }, - { // 13. Return error when unknown flag is passed + { + name: "13. Return error when unknown flag is passed", command: []string{"EXPIREAT", "ExpireAtKey13", "1000", "UNKNOWN"}, presetValues: map[string]KeyData{ "ExpireAtKey13": {Value: "value13", ExpireAt: time.Time{}}, @@ -1414,21 +1533,24 @@ func Test_HandleEXPIREAT(t *testing.T) { expectedValues: nil, expectedError: errors.New("unknown option UNKNOWN"), }, - { // 14. Return error when expire time is not a valid integer + { + name: "14. Return error when expire time is not a valid integer", command: []string{"EXPIREAT", "ExpireAtKey14", "expire"}, presetValues: nil, expectedResponse: 0, expectedValues: nil, expectedError: errors.New("expire time must be integer"), }, - { // 15. Command too short + { + name: "15. Command too short", command: []string{"EXPIREAT"}, presetValues: nil, expectedResponse: 0, expectedValues: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 16. Command too long + { + name: "16. Command too long", command: []string{"EXPIREAT", "ExpireAtKey16", "10", "NX", "GT"}, presetValues: nil, expectedResponse: 0, @@ -1438,62 +1560,64 @@ func Test_HandleEXPIREAT(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("PERSIST, %d", i)) - - if test.presetValues != nil { - for k, v := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, k); err != nil { - t.Error(err) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("PERSIST, %d", i)) + + if test.presetValues != nil { + for k, v := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, k); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, k, v.Value); err != nil { + t.Error(err) + } + mockServer.SetExpiry(ctx, k, v.ExpireAt, false) + mockServer.KeyUnlock(ctx, k) } - if err := mockServer.SetValue(ctx, k, v.Value); err != nil { - t.Error(err) - } - mockServer.SetExpiry(ctx, k, v.ExpireAt, false) - mockServer.KeyUnlock(ctx, k) } - } - res, err := handleExpireAt(ctx, test.command, mockServer, nil) + res, err := handleExpireAt(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err == nil { - t.Errorf("expected error \"%s\", got nil", test.expectedError.Error()) + if test.expectedError != nil { + if err == nil { + t.Errorf("expected error \"%s\", got nil", test.expectedError.Error()) + } + if test.expectedError.Error() != err.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return } - if test.expectedError.Error() != err.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if err != nil { + t.Error(err) } - continue - } - if err != nil { - t.Error(err) - } - - rd := resp.NewReader(bytes.NewReader(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) - } - - if test.expectedValues == nil { - continue - } - - for k, expected := range test.expectedValues { - if _, err = mockServer.KeyLock(ctx, k); err != nil { + + rd := resp.NewReader(bytes.NewReader(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - value := mockServer.GetValue(ctx, k) - expiry := mockServer.GetExpiry(ctx, k) - if value != expected.Value { - t.Errorf("expected value %+v, got %+v", expected.Value, value) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response %d, got %d", test.expectedResponse, rv.Integer()) + } + + if test.expectedValues == nil { + return } - if expiry.UnixMilli() != expected.ExpireAt.UnixMilli() { - t.Errorf("expected expiry %d, got %d", expected.ExpireAt.UnixMilli(), expiry.UnixMilli()) + + for k, expected := range test.expectedValues { + if _, err = mockServer.KeyLock(ctx, k); err != nil { + t.Error(err) + } + value := mockServer.GetValue(ctx, k) + expiry := mockServer.GetExpiry(ctx, k) + if value != expected.Value { + t.Errorf("expected value %+v, got %+v", expected.Value, value) + } + if expiry.UnixMilli() != expected.ExpireAt.UnixMilli() { + t.Errorf("expected expiry %d, got %d", expected.ExpireAt.UnixMilli(), expiry.UnixMilli()) + } + mockServer.KeyUnlock(ctx, k) } - mockServer.KeyUnlock(ctx, k) - } + }) } } diff --git a/pkg/modules/hash/commands_test.go b/pkg/modules/hash/commands_test.go index 28838d0d..1b9e2ac4 100644 --- a/pkg/modules/hash/commands_test.go +++ b/pkg/modules/hash/commands_test.go @@ -41,6 +41,7 @@ func init() { func Test_HandleHSET(t *testing.T) { // Tests for both HSET and HSETNX tests := []struct { + name string preset bool key string presetValue interface{} @@ -49,7 +50,8 @@ func Test_HandleHSET(t *testing.T) { expectedValue map[string]interface{} expectedError error }{ - { // HSETNX set field on non-existent hash map + { + name: "1. HSETNX set field on non-existent hash map", preset: false, key: "HsetKey1", presetValue: map[string]interface{}{}, @@ -58,7 +60,8 @@ func Test_HandleHSET(t *testing.T) { expectedValue: map[string]interface{}{"field1": "value1"}, expectedError: nil, }, - { // HSETNX set field on existing hash map + { + name: "2. HSETNX set field on existing hash map", preset: true, key: "HsetKey2", presetValue: map[string]interface{}{"field1": "value1"}, @@ -67,7 +70,8 @@ func Test_HandleHSET(t *testing.T) { expectedValue: map[string]interface{}{"field1": "value1", "field2": "value2"}, expectedError: nil, }, - { // HSETNX skips operation when setting on existing field + { + name: "3. HSETNX skips operation when setting on existing field", preset: true, key: "HsetKey3", presetValue: map[string]interface{}{"field1": "value1"}, @@ -76,7 +80,8 @@ func Test_HandleHSET(t *testing.T) { expectedValue: map[string]interface{}{"field1": "value1"}, expectedError: nil, }, - { // Regular HSET command on non-existent hash map + { + name: "4. Regular HSET command on non-existent hash map", preset: false, key: "HsetKey4", presetValue: map[string]interface{}{}, @@ -85,7 +90,8 @@ func Test_HandleHSET(t *testing.T) { expectedValue: map[string]interface{}{"field1": "value1", "field2": "value2"}, expectedError: nil, }, - { // Regular HSET update on existing hash map + { + name: "5. Regular HSET update on existing hash map", preset: true, key: "HsetKey5", presetValue: map[string]interface{}{"field1": "value1", "field2": "value2"}, @@ -94,7 +100,8 @@ func Test_HandleHSET(t *testing.T) { expectedValue: map[string]interface{}{"field1": "value1-new", "field2": "value2-ne2", "field3": "value3"}, expectedError: nil, }, - { // HSET returns error when the target key is not a map + { + name: "6. HSET returns error when the target key is not a map", preset: true, key: "HsetKey6", presetValue: "Default preset value", @@ -103,7 +110,8 @@ func Test_HandleHSET(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New("value at HsetKey6 is not a hash"), }, - { // HSET returns error when there's a mismatch in key/values + { + name: "7. HSET returns error when there's a mismatch in key/values", preset: false, key: "HsetKey7", presetValue: nil, @@ -112,7 +120,8 @@ func Test_HandleHSET(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New("each field must have a corresponding value"), }, - { // Command too short + { + name: "8. Command too short", preset: true, key: "HsetKey8", presetValue: nil, @@ -124,50 +133,53 @@ func Test_HandleHSET(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HSET/HSETNX, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HSET/HSETNX, %d", i)) + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleHSET(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response \"%d\", got \"%d\"", test.expectedResponse, rv.Integer()) + } + // Check that all the values are what is expected + if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleHSET(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + hash, ok := mockServer.GetValue(ctx, test.key).(map[string]interface{}) + if !ok { + t.Errorf("value at key \"%s\" is not a hash map", test.key) } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response \"%d\", got \"%d\"", test.expectedResponse, rv.Integer()) - } - // Check that all the values are what is expected - if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { - t.Error(err) - } - hash, ok := mockServer.GetValue(ctx, test.key).(map[string]interface{}) - if !ok { - t.Errorf("value at key \"%s\" is not a hash map", test.key) - } - for field, value := range hash { - if value != test.expectedValue[field] { - t.Errorf("expected value \"%+v\" for field \"%+v\", got \"%+v\"", test.expectedValue[field], field, value) + for field, value := range hash { + if value != test.expectedValue[field] { + t.Errorf("expected value \"%+v\" for field \"%+v\", got \"%+v\"", test.expectedValue[field], field, value) + } } - } + }) } } func Test_HandleHINCRBY(t *testing.T) { // Tests for both HINCRBY and HINCRBYFLOAT tests := []struct { + name string preset bool key string presetValue interface{} @@ -176,7 +188,8 @@ func Test_HandleHINCRBY(t *testing.T) { expectedValue map[string]interface{} expectedError error }{ - { // Increment by integer on non-existent hash should create a new one + { + name: "1. Increment by integer on non-existent hash should create a new one", preset: false, key: "HincrbyKey1", presetValue: nil, @@ -185,7 +198,8 @@ func Test_HandleHINCRBY(t *testing.T) { expectedValue: map[string]interface{}{"field1": 1}, expectedError: nil, }, - { // Increment by float on non-existent hash should create one + { + name: "2. Increment by float on non-existent hash should create one", preset: false, key: "HincrbyKey2", presetValue: nil, @@ -194,7 +208,8 @@ func Test_HandleHINCRBY(t *testing.T) { expectedValue: map[string]interface{}{"field1": 3.142}, expectedError: nil, }, - { // Increment by integer on existing hash + { + name: "3. Increment by integer on existing hash", preset: true, key: "HincrbyKey3", presetValue: map[string]interface{}{"field1": 1}, @@ -203,7 +218,8 @@ func Test_HandleHINCRBY(t *testing.T) { expectedValue: map[string]interface{}{"field1": 11}, expectedError: nil, }, - { // Increment by float on an existing hash + { + name: "4. Increment by float on an existing hash", preset: true, key: "HincrbyKey4", presetValue: map[string]interface{}{"field1": 3.142}, @@ -212,7 +228,8 @@ func Test_HandleHINCRBY(t *testing.T) { expectedValue: map[string]interface{}{"field1": 6.284}, expectedError: nil, }, - { // Command too short + { + name: "5. Command too short", preset: false, key: "HincrbyKey5", presetValue: nil, @@ -221,7 +238,8 @@ func Test_HandleHINCRBY(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Command too long + { + name: "6. Command too long", preset: false, key: "HincrbyKey6", presetValue: nil, @@ -230,7 +248,8 @@ func Test_HandleHINCRBY(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Error when increment by float does not pass valid float + { + name: "7. Error when increment by float does not pass valid float", preset: false, key: "HincrbyKey7", presetValue: nil, @@ -239,7 +258,8 @@ func Test_HandleHINCRBY(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New("increment must be a float"), }, - { // Error when increment does not pass valid integer + { + name: "8. Error when increment does not pass valid integer", preset: false, key: "HincrbyKey8", presetValue: nil, @@ -248,7 +268,8 @@ func Test_HandleHINCRBY(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New("increment must be an integer"), }, - { // Error when trying to increment on a key that is not a hash + { + name: "9. Error when trying to increment on a key that is not a hash", preset: true, key: "HincrbyKey9", presetValue: "Default value", @@ -257,7 +278,8 @@ func Test_HandleHINCRBY(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New("value at HincrbyKey9 is not a hash"), }, - { // Error when trying to increment a hash field that is not a number + { + name: "10. Error when trying to increment a hash field that is not a number", preset: true, key: "HincrbyKey10", presetValue: map[string]interface{}{"field1": "value1"}, @@ -269,59 +291,62 @@ func Test_HandleHINCRBY(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HINCRBY, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HINCRBY, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { - t.Error(err) + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleHINCRBY(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleHINCRBY(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + switch test.expectedResponse.(type) { + default: + t.Error("expectedResponse must be an integer or string") + case int: + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response \"%+v\", got \"%d\"", test.expectedResponse, rv.Integer()) + } + case float64: + if rv.Float() != test.expectedResponse { + t.Errorf("expected response \"%+v\", got \"%+v\"", test.expectedResponse, rv.Float()) + } } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - switch test.expectedResponse.(type) { - default: - t.Error("expectedResponse must be an integer or string") - case int: - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response \"%+v\", got \"%d\"", test.expectedResponse, rv.Integer()) + // Check that all the values are what is expected + if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { + t.Error(err) } - case float64: - if rv.Float() != test.expectedResponse { - t.Errorf("expected response \"%+v\", got \"%+v\"", test.expectedResponse, rv.Float()) + hash, ok := mockServer.GetValue(ctx, test.key).(map[string]interface{}) + if !ok { + t.Errorf("value at key \"%s\" is not a hash map", test.key) } - } - // Check that all the values are what is expected - if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { - t.Error(err) - } - hash, ok := mockServer.GetValue(ctx, test.key).(map[string]interface{}) - if !ok { - t.Errorf("value at key \"%s\" is not a hash map", test.key) - } - for field, value := range hash { - if value != test.expectedValue[field] { - t.Errorf("expected value \"%+v\" for field \"%+v\", got \"%+v\"", test.expectedValue[field], field, value) + for field, value := range hash { + if value != test.expectedValue[field] { + t.Errorf("expected value \"%+v\" for field \"%+v\", got \"%+v\"", test.expectedValue[field], field, value) + } } - } + }) } } func Test_HandleHGET(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -330,7 +355,8 @@ func Test_HandleHGET(t *testing.T) { expectedValue map[string]interface{} expectedError error }{ - { // Return nil when attempting to get from non-existed key + { + name: "1. Return nil when attempting to get from non-existed key", preset: true, key: "HgetKey1", presetValue: map[string]interface{}{"field1": "value1", "field2": 365, "field3": 3.142}, @@ -339,7 +365,8 @@ func Test_HandleHGET(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: nil, }, - { // Return nil when attempting to get from non-existed key + { + name: "2. Return nil when attempting to get from non-existed key", preset: false, key: "HgetKey2", presetValue: map[string]interface{}{}, @@ -348,7 +375,8 @@ func Test_HandleHGET(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: nil, }, - { // Error when trying to get from a value that is not a hash map + { + name: "3. Error when trying to get from a value that is not a hash map", preset: true, key: "HgetKey3", presetValue: "Default Value", @@ -357,7 +385,8 @@ func Test_HandleHGET(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New("value at HgetKey3 is not a hash"), }, - { // Command too short + { + name: "4. Command too short", preset: false, key: "HgetKey4", presetValue: map[string]interface{}{}, @@ -369,59 +398,62 @@ func Test_HandleHGET(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HINCRBY, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HINCRBY, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { - t.Error(err) + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { - t.Error(err) + res, err := handleHGET(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleHGET(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if test.expectedResponse == nil { - if !rv.IsNull() { - t.Errorf("expected nil response, got %+v", rv) + if test.expectedResponse == nil { + if !rv.IsNull() { + t.Errorf("expected nil response, got %+v", rv) + } + return } - continue - } - if expectedArr, ok := test.expectedResponse.([]interface{}); ok { - for i, v := range rv.Array() { - switch v.Type().String() { - default: - t.Error("unexpected type encountered") - case "Integer": - if v.Integer() != expectedArr[i] { - t.Errorf("expected \"%+v\", got \"%d\"", expectedArr[i], v.Integer()) - } - case "BulkString": - if len(v.String()) == 0 && expectedArr[i] == nil { - continue - } - if v.String() != expectedArr[i] { - t.Errorf("expected \"%+v\", got \"%s\"", expectedArr[i], v.String()) + if expectedArr, ok := test.expectedResponse.([]interface{}); ok { + for i, v := range rv.Array() { + switch v.Type().String() { + default: + t.Error("unexpected type encountered") + case "Integer": + if v.Integer() != expectedArr[i] { + t.Errorf("expected \"%+v\", got \"%d\"", expectedArr[i], v.Integer()) + } + case "BulkString": + if len(v.String()) == 0 && expectedArr[i] == nil { + continue + } + if v.String() != expectedArr[i] { + t.Errorf("expected \"%+v\", got \"%s\"", expectedArr[i], v.String()) + } } } } - } + }) } } func Test_HandleHSTRLEN(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -433,6 +465,7 @@ func Test_HandleHSTRLEN(t *testing.T) { { // Return lengths of field values. // If the key does not exist, its length should be 0. + name: "1. Return lengths of field values.", preset: true, key: "HstrlenKey1", presetValue: map[string]interface{}{"field1": "value1", "field2": 123456789, "field3": 3.142}, @@ -441,7 +474,8 @@ func Test_HandleHSTRLEN(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: nil, }, - { // Nil response when trying to get HSTRLEN non-existent key + { + name: "2. Nil response when trying to get HSTRLEN non-existent key", preset: false, key: "HstrlenKey2", presetValue: map[string]interface{}{}, @@ -450,7 +484,8 @@ func Test_HandleHSTRLEN(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: nil, }, - { // Command too short + { + name: "3. Command too short", preset: false, key: "HstrlenKey3", presetValue: map[string]interface{}{}, @@ -459,7 +494,8 @@ func Test_HandleHSTRLEN(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Trying to get lengths on a non hash map returns error + { + name: "4. Trying to get lengths on a non hash map returns error", preset: true, key: "HstrlenKey4", presetValue: "Default value", @@ -471,46 +507,49 @@ func Test_HandleHSTRLEN(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HSTRLEN, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HSTRLEN, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { - t.Error(err) + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { - t.Error(err) + res, err := handleHSTRLEN(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleHSTRLEN(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if test.expectedResponse == nil { - if !rv.IsNull() { - t.Errorf("expected nil response, got %+v", rv) + if test.expectedResponse == nil { + if !rv.IsNull() { + t.Errorf("expected nil response, got %+v", rv) + } + return } - continue - } - expectedResponse, _ := test.expectedResponse.([]int) - for i, v := range rv.Array() { - if v.Integer() != expectedResponse[i] { - t.Errorf("expected \"%d\", got \"%d\"", expectedResponse[i], v.Integer()) + expectedResponse, _ := test.expectedResponse.([]int) + for i, v := range rv.Array() { + if v.Integer() != expectedResponse[i] { + t.Errorf("expected \"%d\", got \"%d\"", expectedResponse[i], v.Integer()) + } } - } + }) } } func Test_HandleHVALS(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -520,7 +559,7 @@ func Test_HandleHVALS(t *testing.T) { expectedError error }{ { - // Return all the values from a hash + name: "1. Return all the values from a hash", preset: true, key: "HvalsKey1", presetValue: map[string]interface{}{"field1": "value1", "field2": 123456789, "field3": 3.142}, @@ -529,7 +568,8 @@ func Test_HandleHVALS(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: nil, }, - { // Empty array response when trying to get HSTRLEN non-existent key + { + name: "2. Empty array response when trying to get HSTRLEN non-existent key", preset: false, key: "HvalsKey2", presetValue: map[string]interface{}{}, @@ -538,7 +578,8 @@ func Test_HandleHVALS(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: nil, }, - { // Command too short + { + name: "3. Command too short", preset: false, key: "HvalsKey3", presetValue: map[string]interface{}{}, @@ -547,7 +588,8 @@ func Test_HandleHVALS(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Command too long + { + name: "4. Command too long", preset: false, key: "HvalsKey4", presetValue: map[string]interface{}{}, @@ -556,7 +598,8 @@ func Test_HandleHVALS(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Trying to get lengths on a non hash map returns error + { + name: "5. Trying to get lengths on a non hash map returns error", preset: true, key: "HvalsKey5", presetValue: "Default value", @@ -568,63 +611,66 @@ func Test_HandleHVALS(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HVALS, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HVALS, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { - t.Error(err) - } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { - t.Error(err) + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleHVALS(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + res, err := handleHVALS(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - switch len(test.expectedResponse) { - case 0: - if len(rv.Array()) != 0 { - t.Errorf("expected empty array, got length \"%d\"", len(rv.Array())) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - default: - for _, v := range rv.Array() { - switch v.Type().String() { - default: - t.Errorf("unexpected error type") - case "Integer": - // Value is an integer, check if it is contained in the expected response - if !slices.ContainsFunc(test.expectedResponse, func(e interface{}) bool { - expectedValue, ok := e.(int) - return ok && expectedValue == v.Integer() - }) { - t.Errorf("couldn't find response value \"%d\" in expected values", v.Integer()) - } - case "BulkString": - // Value is a string, check if it is contained in the expected response - if !slices.ContainsFunc(test.expectedResponse, func(e interface{}) bool { - expectedValue, ok := e.(string) - return ok && expectedValue == v.String() - }) { - t.Errorf("couldn't find response value \"%s\" in expected values", v.String()) + switch len(test.expectedResponse) { + case 0: + if len(rv.Array()) != 0 { + t.Errorf("expected empty array, got length \"%d\"", len(rv.Array())) + } + default: + for _, v := range rv.Array() { + switch v.Type().String() { + default: + t.Errorf("unexpected error type") + case "Integer": + // Value is an integer, check if it is contained in the expected response + if !slices.ContainsFunc(test.expectedResponse, func(e interface{}) bool { + expectedValue, ok := e.(int) + return ok && expectedValue == v.Integer() + }) { + t.Errorf("couldn't find response value \"%d\" in expected values", v.Integer()) + } + case "BulkString": + // Value is a string, check if it is contained in the expected response + if !slices.ContainsFunc(test.expectedResponse, func(e interface{}) bool { + expectedValue, ok := e.(string) + return ok && expectedValue == v.String() + }) { + t.Errorf("couldn't find response value \"%s\" in expected values", v.String()) + } } } } - } + }) } } func Test_HandleHRANDFIELD(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -634,7 +680,8 @@ func Test_HandleHRANDFIELD(t *testing.T) { expectedResponse []string expectedError error }{ - { // Get a random field + { + name: "1. Get a random field", preset: true, key: "HrandfieldKey1", presetValue: map[string]interface{}{"field1": "value1", "field2": 123456789, "field3": 3.142}, @@ -644,7 +691,8 @@ func Test_HandleHRANDFIELD(t *testing.T) { expectedResponse: []string{"field1", "field2", "field3"}, expectedError: nil, }, - { // Get a random field with a value + { + name: "2. Get a random field with a value", preset: true, key: "HrandfieldKey2", presetValue: map[string]interface{}{"field1": "value1", "field2": 123456789, "field3": 3.142}, @@ -654,7 +702,8 @@ func Test_HandleHRANDFIELD(t *testing.T) { expectedResponse: []string{"field1", "value1", "field2", "123456789", "field3", "3.142"}, expectedError: nil, }, - { // Get several random fields + { + name: "3. Get several random fields", preset: true, key: "HrandfieldKey3", presetValue: map[string]interface{}{ @@ -670,7 +719,8 @@ func Test_HandleHRANDFIELD(t *testing.T) { expectedResponse: []string{"field1", "field2", "field3", "field4", "field5"}, expectedError: nil, }, - { // Get several random fields with their corresponding values + { + name: "4. Get several random fields with their corresponding values", preset: true, key: "HrandfieldKey4", presetValue: map[string]interface{}{ @@ -689,7 +739,8 @@ func Test_HandleHRANDFIELD(t *testing.T) { }, expectedError: nil, }, - { // Get the entire hash + { + name: "5. Get the entire hash", preset: true, key: "HrandfieldKey5", presetValue: map[string]interface{}{ @@ -705,7 +756,8 @@ func Test_HandleHRANDFIELD(t *testing.T) { expectedResponse: []string{"field1", "field2", "field3", "field4", "field5"}, expectedError: nil, }, - { // Get the entire hash with values + { + name: "6. Get the entire hash with values", preset: true, key: "HrandfieldKey5", presetValue: map[string]interface{}{ @@ -724,35 +776,40 @@ func Test_HandleHRANDFIELD(t *testing.T) { }, expectedError: nil, }, - { // Command too short + { + name: "7. Command too short", preset: false, key: "HrandfieldKey10", presetValue: map[string]interface{}{}, command: []string{"HRANDFIELD"}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Command too long + { + name: "8. Command too long", preset: false, key: "HrandfieldKey11", presetValue: map[string]interface{}{}, command: []string{"HRANDFIELD", "HrandfieldKey11", "HrandfieldKey11", "HrandfieldKey11", "HrandfieldKey11"}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Trying to get random field on a non hash map returns error + { + name: "9. Trying to get random field on a non hash map returns error", preset: true, key: "HrandfieldKey12", presetValue: "Default value", command: []string{"HRANDFIELD", "HrandfieldKey12"}, expectedError: errors.New("value at HrandfieldKey12 is not a hash"), }, - { // Throw error when count provided is not an integer + { + name: "10. Throw error when count provided is not an integer", preset: true, key: "HrandfieldKey12", presetValue: "Default value", command: []string{"HRANDFIELD", "HrandfieldKey12", "COUNT"}, expectedError: errors.New("count must be an integer"), }, - { // If fourth argument is provided, it must be "WITHVALUES" + { + name: "11. If fourth argument is provided, it must be \"WITHVALUES\"", preset: true, key: "HrandfieldKey12", presetValue: "Default value", @@ -762,65 +819,68 @@ func Test_HandleHRANDFIELD(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HRANDFIELD, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HRANDFIELD, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { - t.Error(err) + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleHRANDFIELD(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleHRANDFIELD(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if len(rv.Array()) != test.expectedCount { + t.Errorf("expected response array of length \"%d\", got length \"%d\"", test.expectedCount, len(rv.Array())) } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if len(rv.Array()) != test.expectedCount { - t.Errorf("expected response array of length \"%d\", got length \"%d\"", test.expectedCount, len(rv.Array())) - } - switch test.withValues { - case false: - for _, v := range rv.Array() { - if !slices.ContainsFunc(test.expectedResponse, func(expected string) bool { - return expected == v.String() - }) { - t.Errorf("could not find response element \"%s\" in expected response", v.String()) + switch test.withValues { + case false: + for _, v := range rv.Array() { + if !slices.ContainsFunc(test.expectedResponse, func(expected string) bool { + return expected == v.String() + }) { + t.Errorf("could not find response element \"%s\" in expected response", v.String()) + } } - } - case true: - responseArray := rv.Array() - for i := 0; i < len(responseArray); i++ { - if i%2 == 0 { - field := responseArray[i].String() - value := responseArray[i+1].String() + case true: + responseArray := rv.Array() + for i := 0; i < len(responseArray); i++ { + if i%2 == 0 { + field := responseArray[i].String() + value := responseArray[i+1].String() - expectedFieldIndex := slices.Index(test.expectedResponse, field) - if expectedFieldIndex == -1 { - t.Errorf("could not find response value \"%s\" in expected values", field) - } - expectedValue := test.expectedResponse[expectedFieldIndex+1] + expectedFieldIndex := slices.Index(test.expectedResponse, field) + if expectedFieldIndex == -1 { + t.Errorf("could not find response value \"%s\" in expected values", field) + } + expectedValue := test.expectedResponse[expectedFieldIndex+1] - if value != expectedValue { - t.Errorf("expected value \"%s\", got \"%s\"", expectedValue, value) + if value != expectedValue { + t.Errorf("expected value \"%s\", got \"%s\"", expectedValue, value) + } } } } - } + }) } } func Test_HandleHLEN(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -830,7 +890,7 @@ func Test_HandleHLEN(t *testing.T) { expectedError error }{ { - // Return the correct length of the hash + name: "1. Return the correct length of the hash", preset: true, key: "HlenKey1", presetValue: map[string]interface{}{"field1": "value1", "field2": 123456789, "field3": 3.142}, @@ -839,7 +899,8 @@ func Test_HandleHLEN(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: nil, }, - { // 0 response when trying to call HLEN on non-existent key + { + name: "2. 0 response when trying to call HLEN on non-existent key", preset: false, key: "HlenKey2", presetValue: map[string]interface{}{}, @@ -848,7 +909,8 @@ func Test_HandleHLEN(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: nil, }, - { // Command too short + { + name: "3. Command too short", preset: false, key: "HlenKey3", presetValue: map[string]interface{}{}, @@ -857,7 +919,8 @@ func Test_HandleHLEN(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Command too long + { + name: "4. Command too long", preset: false, key: "HlenKey4", presetValue: map[string]interface{}{}, @@ -866,7 +929,8 @@ func Test_HandleHLEN(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Trying to get lengths on a non hash map returns error + { + name: "5. Trying to get lengths on a non hash map returns error", preset: true, key: "HlenKey5", presetValue: "Default value", @@ -878,41 +942,44 @@ func Test_HandleHLEN(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HLEN, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HLEN, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { - t.Error(err) + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { - t.Error(err) + res, err := handleHLEN(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleHLEN(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if expectedResponse, ok := test.expectedResponse.(int); ok { - if rv.Integer() != expectedResponse { - t.Errorf("expected ineger \"%d\", got \"%d\"", expectedResponse, rv.Integer()) + if expectedResponse, ok := test.expectedResponse.(int); ok { + if rv.Integer() != expectedResponse { + t.Errorf("expected ineger \"%d\", got \"%d\"", expectedResponse, rv.Integer()) + } + return } - continue - } - t.Error("expected integer response, got another type") + t.Error("expected integer response, got another type") + }) } } func Test_HandleHKeys(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -922,7 +989,7 @@ func Test_HandleHKeys(t *testing.T) { expectedError error }{ { - // Return an array containing all the keys of the hash + name: "1. Return an array containing all the keys of the hash", preset: true, key: "HkeysKey1", presetValue: map[string]interface{}{"field1": "value1", "field2": 123456789, "field3": 3.142}, @@ -931,7 +998,8 @@ func Test_HandleHKeys(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: nil, }, - { // Empty array response when trying to call HKEYS on non-existent key + { + name: "2. Empty array response when trying to call HKEYS on non-existent key", preset: false, key: "HkeysKey2", presetValue: map[string]interface{}{}, @@ -940,7 +1008,8 @@ func Test_HandleHKeys(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: nil, }, - { // Command too short + { + name: "3. Command too short", preset: false, key: "HkeysKey3", presetValue: map[string]interface{}{}, @@ -949,7 +1018,8 @@ func Test_HandleHKeys(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Command too long + { + name: "4. Command too long", preset: false, key: "HkeysKey4", presetValue: map[string]interface{}{}, @@ -958,7 +1028,8 @@ func Test_HandleHKeys(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Trying to get lengths on a non hash map returns error + { + name: "5. Trying to get lengths on a non hash map returns error", preset: true, key: "HkeysKey5", presetValue: "Default value", @@ -970,48 +1041,51 @@ func Test_HandleHKeys(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HKEYS, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HKEYS, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { - t.Error(err) - } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { - t.Error(err) + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleHKEYS(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + res, err := handleHKEYS(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if expectedResponse, ok := test.expectedResponse.([]string); ok { - if len(rv.Array()) != len(expectedResponse) { - t.Errorf("expected length \"%d\", got \"%d\"", len(expectedResponse), len(rv.Array())) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - for _, field := range expectedResponse { - if !slices.ContainsFunc(rv.Array(), func(value resp.Value) bool { - return value.String() == field - }) { - t.Errorf("could not find expected to find key \"%s\" in response", field) + if expectedResponse, ok := test.expectedResponse.([]string); ok { + if len(rv.Array()) != len(expectedResponse) { + t.Errorf("expected length \"%d\", got \"%d\"", len(expectedResponse), len(rv.Array())) } + for _, field := range expectedResponse { + if !slices.ContainsFunc(rv.Array(), func(value resp.Value) bool { + return value.String() == field + }) { + t.Errorf("could not find expected to find key \"%s\" in response", field) + } + } + return } - continue - } - t.Error("expected array response, got another type") + t.Error("expected array response, got another type") + }) } } func Test_HandleHGETALL(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -1021,7 +1095,7 @@ func Test_HandleHGETALL(t *testing.T) { expectedError error }{ { - // Return an array containing all the fields and values of the hash + name: "1. Return an array containing all the fields and values of the hash", preset: true, key: "HGetAllKey1", presetValue: map[string]interface{}{"field1": "value1", "field2": 123456789, "field3": 3.142}, @@ -1030,7 +1104,8 @@ func Test_HandleHGETALL(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: nil, }, - { // Empty array response when trying to call HGETALL on non-existent key + { + name: "2. Empty array response when trying to call HGETALL on non-existent key", preset: false, key: "HGetAllKey2", presetValue: map[string]interface{}{}, @@ -1039,7 +1114,8 @@ func Test_HandleHGETALL(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: nil, }, - { // Command too short + { + name: "3. Command too short", preset: false, key: "HGetAllKey3", presetValue: map[string]interface{}{}, @@ -1048,7 +1124,8 @@ func Test_HandleHGETALL(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Command too long + { + name: "4. Command too long", preset: false, key: "HGetAllKey4", presetValue: map[string]interface{}{}, @@ -1057,7 +1134,8 @@ func Test_HandleHGETALL(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Trying to get lengths on a non hash map returns error + { + name: "5. Trying to get lengths on a non hash map returns error", preset: true, key: "HGetAllKey5", presetValue: "Default value", @@ -1069,59 +1147,62 @@ func Test_HandleHGETALL(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HGETALL, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HGETALL, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { - t.Error(err) + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleHGETALL(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleHGETALL(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if len(rv.Array()) != len(test.expectedResponse) { + t.Errorf("expected length \"%d\", got \"%d\"", len(test.expectedResponse), len(rv.Array())) } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if len(rv.Array()) != len(test.expectedResponse) { - t.Errorf("expected length \"%d\", got \"%d\"", len(test.expectedResponse), len(rv.Array())) - } - // In the response: - // The order of results is not guaranteed, - // However, each field in the array will be reliably followed by its corresponding value - responseArray := rv.Array() - for i := 0; i < len(responseArray); i++ { - if i%2 == 0 { - // We're on a field in the response - field := responseArray[i].String() - value := responseArray[i+1].String() + // In the response: + // The order of results is not guaranteed, + // However, each field in the array will be reliably followed by its corresponding value + responseArray := rv.Array() + for i := 0; i < len(responseArray); i++ { + if i%2 == 0 { + // We're on a field in the response + field := responseArray[i].String() + value := responseArray[i+1].String() - expectedFieldIndex := slices.Index(test.expectedResponse, field) - if expectedFieldIndex == -1 { - t.Errorf("received unexpected field \"%s\" in response", field) - } - expectedValue := test.expectedResponse[expectedFieldIndex+1] - if expectedValue != value { - t.Errorf("expected entry \"%s\", got \"%s\"", expectedValue, value) + expectedFieldIndex := slices.Index(test.expectedResponse, field) + if expectedFieldIndex == -1 { + t.Errorf("received unexpected field \"%s\" in response", field) + } + expectedValue := test.expectedResponse[expectedFieldIndex+1] + if expectedValue != value { + t.Errorf("expected entry \"%s\", got \"%s\"", expectedValue, value) + } } - } - } - continue + } + return + }) } } func Test_HandleHEXISTS(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -1131,7 +1212,7 @@ func Test_HandleHEXISTS(t *testing.T) { expectedError error }{ { - // Return 1 if the field exists in the hash + name: "1. Return 1 if the field exists in the hash", preset: true, key: "HexistsKey1", presetValue: map[string]interface{}{"field1": "value1", "field2": 123456789, "field3": 3.142}, @@ -1140,7 +1221,8 @@ func Test_HandleHEXISTS(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: nil, }, - { // 0 response when trying to call HEXISTS on non-existent key + { + name: "2. 0 response when trying to call HEXISTS on non-existent key", preset: false, key: "HexistsKey2", presetValue: map[string]interface{}{}, @@ -1149,7 +1231,8 @@ func Test_HandleHEXISTS(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: nil, }, - { // Command too short + { + name: "3. Command too short", preset: false, key: "HexistsKey3", presetValue: map[string]interface{}{}, @@ -1158,7 +1241,8 @@ func Test_HandleHEXISTS(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Command too long + { + name: "4. Command too long", preset: false, key: "HexistsKey4", presetValue: map[string]interface{}{}, @@ -1167,7 +1251,8 @@ func Test_HandleHEXISTS(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Trying to get lengths on a non hash map returns error + { + name: "5. Trying to get lengths on a non hash map returns error", preset: true, key: "HexistsKey5", presetValue: "Default value", @@ -1179,41 +1264,44 @@ func Test_HandleHEXISTS(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HEXISTS, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HEXISTS, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { - t.Error(err) + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { - t.Error(err) + res, err := handleHEXISTS(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleHEXISTS(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if expectedResponse, ok := test.expectedResponse.(int); ok { - if rv.Integer() != expectedResponse { - t.Errorf("expected \"%d\", got \"%d\"", expectedResponse, rv.Integer()) + if expectedResponse, ok := test.expectedResponse.(int); ok { + if rv.Integer() != expectedResponse { + t.Errorf("expected \"%d\", got \"%d\"", expectedResponse, rv.Integer()) + } + return } - continue - } - t.Error("expected integer response, got another type") + t.Error("expected integer response, got another type") + }) } } func Test_HandleHDEL(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -1223,7 +1311,7 @@ func Test_HandleHDEL(t *testing.T) { expectedError error }{ { - // Return count of deleted fields in the specified hash + name: "1. Return count of deleted fields in the specified hash", preset: true, key: "HdelKey1", presetValue: map[string]interface{}{"field1": "value1", "field2": 123456789, "field3": 3.142, "field7": "value7"}, @@ -1232,7 +1320,8 @@ func Test_HandleHDEL(t *testing.T) { expectedValue: map[string]interface{}{"field1": nil, "field2": nil, "field3": nil, "field7": "value1"}, expectedError: nil, }, - { // 0 response when passing delete fields that are non-existent on valid hash + { + name: "2. 0 response when passing delete fields that are non-existent on valid hash", preset: true, key: "HdelKey2", presetValue: map[string]interface{}{"field1": "value1", "field2": "value2", "field3": "value3"}, @@ -1241,7 +1330,8 @@ func Test_HandleHDEL(t *testing.T) { expectedValue: map[string]interface{}{"field1": "value1", "field2": "value2", "field3": "value3"}, expectedError: nil, }, - { // 0 response when trying to call HDEL on non-existent key + { + name: "3. 0 response when trying to call HDEL on non-existent key", preset: false, key: "HdelKey3", presetValue: map[string]interface{}{}, @@ -1250,7 +1340,8 @@ func Test_HandleHDEL(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: nil, }, - { // Command too short + { + name: "4. Command too short", preset: false, key: "HdelKey4", presetValue: map[string]interface{}{}, @@ -1259,7 +1350,8 @@ func Test_HandleHDEL(t *testing.T) { expectedValue: map[string]interface{}{}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Trying to get lengths on a non hash map returns error + { + name: "5. Trying to get lengths on a non hash map returns error", preset: true, key: "HdelKey5", presetValue: "Default value", @@ -1271,46 +1363,48 @@ func Test_HandleHDEL(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HDEL, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("HDEL, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { - t.Error(err) + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleHDEL(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleHDEL(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + if expectedResponse, ok := test.expectedResponse.(int); ok { + if rv.Integer() != expectedResponse { + t.Errorf("expected \"%d\", got \"%d\"", expectedResponse, rv.Integer()) + } + return } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if expectedResponse, ok := test.expectedResponse.(int); ok { - if rv.Integer() != expectedResponse { - t.Errorf("expected \"%d\", got \"%d\"", expectedResponse, rv.Integer()) + if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { + t.Error(err) } - continue - } - if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { - t.Error(err) - } - if hash, ok := mockServer.GetValue(ctx, test.key).(map[string]interface{}); ok { - for field, value := range hash { - if value != test.expectedValue[field] { - t.Errorf("expected value \"%+v\", got \"%+v\"", test.expectedValue[field], value) + if hash, ok := mockServer.GetValue(ctx, test.key).(map[string]interface{}); ok { + for field, value := range hash { + if value != test.expectedValue[field] { + t.Errorf("expected value \"%+v\", got \"%+v\"", test.expectedValue[field], value) + } } + return } - continue - } - t.Error("expected hash value but got another type") + t.Error("expected hash value but got another type") + }) } } diff --git a/pkg/modules/list/commands_test.go b/pkg/modules/list/commands_test.go index 204c793d..94ecab10 100644 --- a/pkg/modules/list/commands_test.go +++ b/pkg/modules/list/commands_test.go @@ -39,6 +39,7 @@ func init() { func Test_HandleLLEN(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -47,7 +48,8 @@ func Test_HandleLLEN(t *testing.T) { expectedValue []interface{} expectedError error }{ - { // If key exists and is a list, return the lists length + { + name: "1. If key exists and is a list, return the lists length", preset: true, key: "LlenKey1", presetValue: []interface{}{"value1", "value2", "value3", "value4"}, @@ -56,7 +58,8 @@ func Test_HandleLLEN(t *testing.T) { expectedValue: nil, expectedError: nil, }, - { // If key does not exist, return 0 + { + name: "2. If key does not exist, return 0", preset: false, key: "LlenKey2", presetValue: nil, @@ -65,7 +68,8 @@ func Test_HandleLLEN(t *testing.T) { expectedValue: nil, expectedError: nil, }, - { // Command too short + { + name: "3. Command too short", preset: false, key: "LlenKey3", presetValue: nil, @@ -74,7 +78,8 @@ func Test_HandleLLEN(t *testing.T) { expectedValue: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Command too long + { + name: "4. Command too long", preset: false, key: "LlenKey4", presetValue: nil, @@ -83,7 +88,8 @@ func Test_HandleLLEN(t *testing.T) { expectedValue: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Trying to get lengths on a non-list returns error + { + name: "5. Trying to get lengths on a non-list returns error", preset: true, key: "LlenKey5", presetValue: "Default value", @@ -95,37 +101,40 @@ func Test_HandleLLEN(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("LLEN, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("LLEN, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { - t.Error(err) + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + res, err := handleLLen(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleLLen(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected integer response \"%d\", got \"%d\"", test.expectedResponse, rv.Integer()) - } + if rv.Integer() != test.expectedResponse { + t.Errorf("expected integer response \"%d\", got \"%d\"", test.expectedResponse, rv.Integer()) + } + }) } } func Test_HandleLINDEX(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -134,7 +143,8 @@ func Test_HandleLINDEX(t *testing.T) { expectedValue []interface{} expectedError error }{ - { // Return last element within range + { + name: "1. Return last element within range", preset: true, key: "LindexKey1", presetValue: []interface{}{"value1", "value2", "value3", "value4"}, @@ -143,7 +153,8 @@ func Test_HandleLINDEX(t *testing.T) { expectedValue: nil, expectedError: nil, }, - { // Return first element within range + { + name: "2. Return first element within range", preset: true, key: "LindexKey2", presetValue: []interface{}{"value1", "value2", "value3", "value4"}, @@ -152,7 +163,8 @@ func Test_HandleLINDEX(t *testing.T) { expectedValue: nil, expectedError: nil, }, - { // Return middle element within range + { + name: "3. Return middle element within range", preset: true, key: "LindexKey3", presetValue: []interface{}{"value1", "value2", "value3", "value4"}, @@ -161,7 +173,8 @@ func Test_HandleLINDEX(t *testing.T) { expectedValue: nil, expectedError: nil, }, - { // If key does not exist, return error + { + name: "4. If key does not exist, return error", preset: false, key: "LindexKey4", presetValue: nil, @@ -170,7 +183,8 @@ func Test_HandleLINDEX(t *testing.T) { expectedValue: nil, expectedError: errors.New("LINDEX command on non-list item"), }, - { // Command too short + { + name: "5. Command too short", preset: false, key: "LindexKey3", presetValue: nil, @@ -179,7 +193,8 @@ func Test_HandleLINDEX(t *testing.T) { expectedValue: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Command too long + { + name: " 6. Command too long", preset: false, key: "LindexKey4", presetValue: nil, @@ -188,7 +203,8 @@ func Test_HandleLINDEX(t *testing.T) { expectedValue: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Trying to get element by index on a non-list returns error + { + name: "7. Trying to get element by index on a non-list returns error", preset: true, key: "LindexKey5", presetValue: "Default value", @@ -197,7 +213,8 @@ func Test_HandleLINDEX(t *testing.T) { expectedValue: nil, expectedError: errors.New("LINDEX command on non-list item"), }, - { // Trying to get index out of range index beyond last index + { + name: "8. Trying to get index out of range index beyond last index", preset: true, key: "LindexKey6", presetValue: []interface{}{"value1", "value2", "value3"}, @@ -206,7 +223,8 @@ func Test_HandleLINDEX(t *testing.T) { expectedValue: nil, expectedError: errors.New("index must be within list range"), }, - { // Trying to get index out of range with negative index + { + name: "9. Trying to get index out of range with negative index", preset: true, key: "LindexKey7", presetValue: []interface{}{"value1", "value2", "value3"}, @@ -215,7 +233,8 @@ func Test_HandleLINDEX(t *testing.T) { expectedValue: nil, expectedError: errors.New("index must be within list range"), }, - { // Return error when index is not an integer + { + name: " 10. Return error when index is not an integer", preset: false, key: "LindexKey8", presetValue: []interface{}{"value1", "value2", "value3"}, @@ -227,37 +246,40 @@ func Test_HandleLINDEX(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("LINDEX, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("LINDEX, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { - t.Error(err) + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + res, err := handleLIndex(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleLIndex(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.String() != test.expectedResponse { - t.Errorf("expected response \"%s\", got \"%s\"", test.expectedResponse, rv.String()) - } + if rv.String() != test.expectedResponse { + t.Errorf("expected response \"%s\", got \"%s\"", test.expectedResponse, rv.String()) + } + }) } } func Test_HandleLRANGE(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -270,6 +292,7 @@ func Test_HandleLRANGE(t *testing.T) { // Return sub-list within range. // Both start and end indices are positive. // End index is greater than start index. + name: "1. Return sub-list within range.", preset: true, key: "LrangeKey1", presetValue: []interface{}{"value1", "value2", "value3", "value4", "value5", "value6", "value7", "value8"}, @@ -278,7 +301,8 @@ func Test_HandleLRANGE(t *testing.T) { expectedValue: nil, expectedError: nil, }, - { // Return sub-list from start index to the end of the list when end index is -1 + { + name: "2. Return sub-list from start index to the end of the list when end index is -1", preset: true, key: "LrangeKey2", presetValue: []interface{}{"value1", "value2", "value3", "value4", "value5", "value6", "value7", "value8"}, @@ -287,7 +311,8 @@ func Test_HandleLRANGE(t *testing.T) { expectedValue: nil, expectedError: nil, }, - { // Return the reversed sub-list when the end index is greater than -1 but less than start index + { + name: "3. Return the reversed sub-list when the end index is greater than -1 but less than start index", preset: true, key: "LrangeKey3", presetValue: []interface{}{"value1", "value2", "value3", "value4", "value5", "value6", "value7", "value8"}, @@ -296,7 +321,8 @@ func Test_HandleLRANGE(t *testing.T) { expectedValue: nil, expectedError: nil, }, - { // If key does not exist, return error + { + name: "4. If key does not exist, return error", preset: false, key: "LrangeKey4", presetValue: nil, @@ -305,7 +331,8 @@ func Test_HandleLRANGE(t *testing.T) { expectedValue: nil, expectedError: errors.New("LRANGE command on non-list item"), }, - { // Command too short + { + name: "5. Command too short", preset: false, key: "LrangeKey5", presetValue: nil, @@ -314,7 +341,8 @@ func Test_HandleLRANGE(t *testing.T) { expectedValue: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Command too long + { + name: "6. Command too long", preset: false, key: "LrangeKey6", presetValue: nil, @@ -323,7 +351,8 @@ func Test_HandleLRANGE(t *testing.T) { expectedValue: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Error when executing command on non-list command + { + name: "7. Error when executing command on non-list command", preset: true, key: "LrangeKey5", presetValue: "Default value", @@ -332,7 +361,8 @@ func Test_HandleLRANGE(t *testing.T) { expectedValue: nil, expectedError: errors.New("LRANGE command on non-list item"), }, - { // Error when start index is less than 0 + { + name: "8. Error when start index is less than 0", preset: true, key: "LrangeKey7", presetValue: []interface{}{"value1", "value2", "value3", "value4"}, @@ -341,7 +371,8 @@ func Test_HandleLRANGE(t *testing.T) { expectedValue: nil, expectedError: errors.New("start index must be within list boundary"), }, - { // Error when start index is higher than the length of the list + { + name: "9. Error when start index is higher than the length of the list", preset: true, key: "LrangeKey8", presetValue: []interface{}{"value1", "value2", "value3"}, @@ -350,7 +381,8 @@ func Test_HandleLRANGE(t *testing.T) { expectedValue: nil, expectedError: errors.New("start index must be within list boundary"), }, - { // Return error when start index is not an integer + { + name: "10. Return error when start index is not an integer", preset: false, key: "LrangeKey9", presetValue: []interface{}{"value1", "value2", "value3"}, @@ -359,7 +391,8 @@ func Test_HandleLRANGE(t *testing.T) { expectedValue: nil, expectedError: errors.New("start and end indices must be integers"), }, - { // Return error when end index is not an integer + { + name: "11. Return error when end index is not an integer", preset: false, key: "LrangeKey10", presetValue: []interface{}{"value1", "value2", "value3"}, @@ -368,7 +401,8 @@ func Test_HandleLRANGE(t *testing.T) { expectedValue: nil, expectedError: errors.New("start and end indices must be integers"), }, - { // Error when start and end indices are equal + { + name: "12. Error when start and end indices are equal", preset: true, key: "LrangeKey11", presetValue: []interface{}{"value1", "value2", "value3"}, @@ -380,43 +414,46 @@ func Test_HandleLRANGE(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("LRANGE, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("LRANGE, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { - t.Error(err) + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + res, err := handleLRange(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleLRange(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - responseArray := rv.Array() - if len(responseArray) != len(test.expectedResponse) { - t.Errorf("expected response of length \"%d\", got \"%d\"", len(test.expectedResponse), len(responseArray)) - } - for i := 0; i < len(responseArray); i++ { - if responseArray[i].String() != test.expectedResponse[i] { - t.Errorf("expected value \"%s\" at index %d, got \"%s\"", test.expectedResponse[i], i, responseArray[i].String()) - } - } + responseArray := rv.Array() + if len(responseArray) != len(test.expectedResponse) { + t.Errorf("expected response of length \"%d\", got \"%d\"", len(test.expectedResponse), len(responseArray)) + } + for i := 0; i < len(responseArray); i++ { + if responseArray[i].String() != test.expectedResponse[i] { + t.Errorf("expected value \"%s\" at index %d, got \"%s\"", test.expectedResponse[i], i, responseArray[i].String()) + } + } + }) } } func Test_HandleLSET(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -425,7 +462,8 @@ func Test_HandleLSET(t *testing.T) { expectedValue []interface{} expectedError error }{ - { // Return last element within range + { + name: "1. Return last element within range", preset: true, key: "LsetKey1", presetValue: []interface{}{"value1", "value2", "value3", "value4"}, @@ -434,7 +472,8 @@ func Test_HandleLSET(t *testing.T) { expectedValue: []interface{}{"value1", "value2", "value3", "new-value"}, expectedError: nil, }, - { // Return first element within range + { + name: "2. Return first element within range", preset: true, key: "LsetKey2", presetValue: []interface{}{"value1", "value2", "value3", "value4"}, @@ -443,7 +482,8 @@ func Test_HandleLSET(t *testing.T) { expectedValue: []interface{}{"new-value", "value2", "value3", "value4"}, expectedError: nil, }, - { // Return middle element within range + { + name: "3. Return middle element within range", preset: true, key: "LsetKey3", presetValue: []interface{}{"value1", "value2", "value3", "value4"}, @@ -452,7 +492,8 @@ func Test_HandleLSET(t *testing.T) { expectedValue: []interface{}{"value1", "new-value", "value3", "value4"}, expectedError: nil, }, - { // If key does not exist, return error + { + name: "4. If key does not exist, return error", preset: false, key: "LsetKey4", presetValue: nil, @@ -461,7 +502,8 @@ func Test_HandleLSET(t *testing.T) { expectedValue: nil, expectedError: errors.New("LSET command on non-list item"), }, - { // Command too short + { + name: "5. Command too short", preset: false, key: "LsetKey5", presetValue: nil, @@ -470,7 +512,8 @@ func Test_HandleLSET(t *testing.T) { expectedValue: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Command too long + { + name: "6. Command too long", preset: false, key: "LsetKey6", presetValue: nil, @@ -479,7 +522,8 @@ func Test_HandleLSET(t *testing.T) { expectedValue: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Trying to get element by index on a non-list returns error + { + name: "7. Trying to get element by index on a non-list returns error", preset: true, key: "LsetKey5", presetValue: "Default value", @@ -488,7 +532,8 @@ func Test_HandleLSET(t *testing.T) { expectedValue: nil, expectedError: errors.New("LSET command on non-list item"), }, - { // Trying to get index out of range index beyond last index + { + name: "8. Trying to get index out of range index beyond last index", preset: true, key: "LsetKey6", presetValue: []interface{}{"value1", "value2", "value3"}, @@ -497,7 +542,8 @@ func Test_HandleLSET(t *testing.T) { expectedValue: nil, expectedError: errors.New("index must be within list range"), }, - { // Trying to get index out of range with negative index + { + name: "9. Trying to get index out of range with negative index", preset: true, key: "LsetKey7", presetValue: []interface{}{"value1", "value2", "value3"}, @@ -506,7 +552,8 @@ func Test_HandleLSET(t *testing.T) { expectedValue: nil, expectedError: errors.New("index must be within list range"), }, - { // Return error when index is not an integer + { + name: "10. Return error when index is not an integer", preset: false, key: "LsetKey8", presetValue: []interface{}{"value1", "value2", "value3"}, @@ -518,53 +565,56 @@ func Test_HandleLSET(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("LSET, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("LSET, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleLSet(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + if rv.String() != test.expectedResponse { + t.Errorf("expected \"%s\" response, got \"%s\"", test.expectedResponse, rv.String()) + } + if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleLSet(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.String() != test.expectedResponse { - t.Errorf("expected \"%s\" response, got \"%s\"", test.expectedResponse, rv.String()) - } - if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { - t.Error(err) - } - list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) - if !ok { - t.Error("expected value to be list, got another type") - } - if len(list) != len(test.expectedValue) { - t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) - } - for i := 0; i < len(list); i++ { - if list[i] != test.expectedValue[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) - } - } - mockServer.KeyRUnlock(ctx, test.key) + list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) + if !ok { + t.Error("expected value to be list, got another type") + } + if len(list) != len(test.expectedValue) { + t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) + } + for i := 0; i < len(list); i++ { + if list[i] != test.expectedValue[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) + } + } + mockServer.KeyRUnlock(ctx, test.key) + }) } } func Test_HandleLTRIM(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -577,6 +627,7 @@ func Test_HandleLTRIM(t *testing.T) { // Return trim within range. // Both start and end indices are positive. // End index is greater than start index. + name: "1. Return trim within range.", preset: true, key: "LtrimKey1", presetValue: []interface{}{"value1", "value2", "value3", "value4", "value5", "value6", "value7", "value8"}, @@ -585,7 +636,8 @@ func Test_HandleLTRIM(t *testing.T) { expectedValue: []interface{}{"value4", "value5", "value6"}, expectedError: nil, }, - { // Return element from start index to end index when end index is greater than length of the list + { + name: "2. Return element from start index to end index when end index is greater than length of the list", preset: true, key: "LtrimKey2", presetValue: []interface{}{"value1", "value2", "value3", "value4", "value5", "value6", "value7", "value8"}, @@ -594,7 +646,8 @@ func Test_HandleLTRIM(t *testing.T) { expectedValue: []interface{}{"value6", "value7", "value8"}, expectedError: nil, }, - { // Return error when end index is smaller than start index but greater than -1 + { + name: "3. Return error when end index is smaller than start index but greater than -1", preset: true, key: "LtrimKey3", presetValue: []interface{}{"value1", "value2", "value3", "value4"}, @@ -603,7 +656,8 @@ func Test_HandleLTRIM(t *testing.T) { expectedValue: nil, expectedError: errors.New("end index must be greater than start index or -1"), }, - { // If key does not exist, return error + { + name: "4. If key does not exist, return error", preset: false, key: "LtrimKey4", presetValue: nil, @@ -612,7 +666,8 @@ func Test_HandleLTRIM(t *testing.T) { expectedValue: nil, expectedError: errors.New("LTRIM command on non-list item"), }, - { // Command too short + { + name: "5. Command too short", preset: false, key: "LtrimKey5", presetValue: nil, @@ -621,7 +676,8 @@ func Test_HandleLTRIM(t *testing.T) { expectedValue: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Command too long + { + name: "6. Command too long", preset: false, key: "LtrimKey6", presetValue: nil, @@ -630,7 +686,8 @@ func Test_HandleLTRIM(t *testing.T) { expectedValue: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Trying to get element by index on a non-list returns error + { + name: "7. Trying to get element by index on a non-list returns error", preset: true, key: "LtrimKey5", presetValue: "Default value", @@ -639,7 +696,8 @@ func Test_HandleLTRIM(t *testing.T) { expectedValue: nil, expectedError: errors.New("LTRIM command on non-list item"), }, - { // Error when start index is less than 0 + { + name: "8. Error when start index is less than 0", preset: true, key: "LtrimKey7", presetValue: []interface{}{"value1", "value2", "value3", "value4"}, @@ -648,7 +706,8 @@ func Test_HandleLTRIM(t *testing.T) { expectedValue: nil, expectedError: errors.New("start index must be within list boundary"), }, - { // Error when start index is higher than the length of the list + { + name: "9. Error when start index is higher than the length of the list", preset: true, key: "LtrimKey8", presetValue: []interface{}{"value1", "value2", "value3"}, @@ -657,7 +716,8 @@ func Test_HandleLTRIM(t *testing.T) { expectedValue: nil, expectedError: errors.New("start index must be within list boundary"), }, - { // Return error when start index is not an integer + { + name: "10. Return error when start index is not an integer", preset: false, key: "LtrimKey9", presetValue: []interface{}{"value1", "value2", "value3"}, @@ -666,7 +726,8 @@ func Test_HandleLTRIM(t *testing.T) { expectedValue: nil, expectedError: errors.New("start and end indices must be integers"), }, - { // Return error when end index is not an integer + { + name: "11. Return error when end index is not an integer", preset: false, key: "LtrimKey10", presetValue: []interface{}{"value1", "value2", "value3"}, @@ -678,53 +739,56 @@ func Test_HandleLTRIM(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("LTRIM, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("LTRIM, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleLTrim(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + if rv.String() != test.expectedResponse { + t.Errorf("expected \"%s\" response, got \"%s\"", test.expectedResponse, rv.String()) + } + if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleLTrim(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.String() != test.expectedResponse { - t.Errorf("expected \"%s\" response, got \"%s\"", test.expectedResponse, rv.String()) - } - if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { - t.Error(err) - } - list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) - if !ok { - t.Error("expected value to be list, got another type") - } - if len(list) != len(test.expectedValue) { - t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) - } - for i := 0; i < len(list); i++ { - if list[i] != test.expectedValue[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) - } - } - mockServer.KeyRUnlock(ctx, test.key) + list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) + if !ok { + t.Error("expected value to be list, got another type") + } + if len(list) != len(test.expectedValue) { + t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) + } + for i := 0; i < len(list); i++ { + if list[i] != test.expectedValue[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) + } + } + mockServer.KeyRUnlock(ctx, test.key) + }) } } func Test_HandleLREM(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -733,7 +797,8 @@ func Test_HandleLREM(t *testing.T) { expectedValue []interface{} expectedError error }{ - { // Remove the first 3 elements that appear in the list + { + name: "1. Remove the first 3 elements that appear in the list", preset: true, key: "LremKey1", presetValue: []interface{}{"1", "2", "4", "4", "5", "6", "7", "4", "8", "4", "9", "10", "5", "4"}, @@ -742,7 +807,8 @@ func Test_HandleLREM(t *testing.T) { expectedValue: []interface{}{"1", "2", "5", "6", "7", "8", "4", "9", "10", "5", "4"}, expectedError: nil, }, - { // Remove the last 3 elements that appear in the list + { + name: "2. Remove the last 3 elements that appear in the list", preset: true, key: "LremKey1", presetValue: []interface{}{"1", "2", "4", "4", "5", "6", "7", "4", "8", "4", "9", "10", "5", "4"}, @@ -751,7 +817,8 @@ func Test_HandleLREM(t *testing.T) { expectedValue: []interface{}{"1", "2", "4", "4", "5", "6", "7", "8", "9", "10", "5"}, expectedError: nil, }, - { // Command too short + { + name: "3. Command too short", preset: false, key: "LremKey5", presetValue: nil, @@ -760,7 +827,8 @@ func Test_HandleLREM(t *testing.T) { expectedValue: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Command too long + { + name: "4. Command too long", preset: false, key: "LremKey6", presetValue: nil, @@ -769,7 +837,8 @@ func Test_HandleLREM(t *testing.T) { expectedValue: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Throw error when count is not an integer + { + name: "5. Throw error when count is not an integer", preset: false, key: "LremKey7", presetValue: nil, @@ -778,7 +847,8 @@ func Test_HandleLREM(t *testing.T) { expectedValue: nil, expectedError: errors.New("count must be an integer"), }, - { // Throw error on non-list item + { + name: "6. Throw error on non-list item", preset: true, key: "LremKey8", presetValue: "Default value", @@ -787,7 +857,8 @@ func Test_HandleLREM(t *testing.T) { expectedValue: nil, expectedError: errors.New("LREM command on non-list item"), }, - { // Throw error on non-existent item + { + name: "7. Throw error on non-existent item", preset: false, key: "LremKey9", presetValue: "Default value", @@ -799,53 +870,56 @@ func Test_HandleLREM(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("LREM, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("LREM, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleLRem(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + if rv.String() != test.expectedResponse { + t.Errorf("expected \"%s\" response, got \"%s\"", test.expectedResponse, rv.String()) + } + if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleLRem(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.String() != test.expectedResponse { - t.Errorf("expected \"%s\" response, got \"%s\"", test.expectedResponse, rv.String()) - } - if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { - t.Error(err) - } - list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) - if !ok { - t.Error("expected value to be list, got another type") - } - if len(list) != len(test.expectedValue) { - t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) - } - for i := 0; i < len(list); i++ { - if list[i] != test.expectedValue[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) - } - } - mockServer.KeyRUnlock(ctx, test.key) + list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) + if !ok { + t.Error("expected value to be list, got another type") + } + if len(list) != len(test.expectedValue) { + t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) + } + for i := 0; i < len(list); i++ { + if list[i] != test.expectedValue[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) + } + } + mockServer.KeyRUnlock(ctx, test.key) + }) } } func Test_HandleLMOVE(t *testing.T) { tests := []struct { + name string preset bool presetValue map[string]interface{} command []string @@ -854,7 +928,7 @@ func Test_HandleLMOVE(t *testing.T) { expectedError error }{ { - // 1. Move element from LEFT of left list to LEFT of right list + name: "1. Move element from LEFT of left list to LEFT of right list", preset: true, presetValue: map[string]interface{}{ "source1": []interface{}{"one", "two", "three"}, @@ -869,7 +943,7 @@ func Test_HandleLMOVE(t *testing.T) { expectedError: nil, }, { - // 2. Move element from LEFT of left list to RIGHT of right list + name: "2. Move element from LEFT of left list to RIGHT of right list", preset: true, presetValue: map[string]interface{}{ "source2": []interface{}{"one", "two", "three"}, @@ -884,7 +958,7 @@ func Test_HandleLMOVE(t *testing.T) { expectedError: nil, }, { - // 3. Move element from RIGHT of left list to LEFT of right list + name: "3. Move element from RIGHT of left list to LEFT of right list", preset: true, presetValue: map[string]interface{}{ "source3": []interface{}{"one", "two", "three"}, @@ -899,7 +973,7 @@ func Test_HandleLMOVE(t *testing.T) { expectedError: nil, }, { - // 4. Move element from RIGHT of left list to RIGHT of right list + name: "4. Move element from RIGHT of left list to RIGHT of right list", preset: true, presetValue: map[string]interface{}{ "source4": []interface{}{"one", "two", "three"}, @@ -914,7 +988,7 @@ func Test_HandleLMOVE(t *testing.T) { expectedError: nil, }, { - // 5. Throw error when the right list is non-existent + name: "5. Throw error when the right list is non-existent", preset: true, presetValue: map[string]interface{}{ "source5": []interface{}{"one", "two", "three"}, @@ -927,7 +1001,7 @@ func Test_HandleLMOVE(t *testing.T) { expectedError: errors.New("both source and destination must be lists"), }, { - // 6. Throw error when right list in not a list + name: "6. Throw error when right list in not a list", preset: true, presetValue: map[string]interface{}{ "source6": []interface{}{"one", "two", "tree"}, @@ -942,7 +1016,7 @@ func Test_HandleLMOVE(t *testing.T) { expectedError: errors.New("both source and destination must be lists"), }, { - // 7. Throw error when left list is non-existent + name: "7. Throw error when left list is non-existent", preset: true, presetValue: map[string]interface{}{ "destination7": []interface{}{"one", "two", "three"}, @@ -955,7 +1029,7 @@ func Test_HandleLMOVE(t *testing.T) { expectedError: errors.New("both source and destination must be lists"), }, { - // 8. Throw error when left list is not a list + name: "8. Throw error when left list is not a list", preset: true, presetValue: map[string]interface{}{ "source8": "Default value", @@ -970,7 +1044,7 @@ func Test_HandleLMOVE(t *testing.T) { expectedError: errors.New("both source and destination must be lists"), }, { - // 9. Throw error when command is too short + name: "9. Throw error when command is too short", preset: false, presetValue: map[string]interface{}{}, command: []string{"LMOVE", "source9", "destination9"}, @@ -979,7 +1053,7 @@ func Test_HandleLMOVE(t *testing.T) { expectedError: errors.New(constants.WrongArgsResponse), }, { - // 10. Throw error when command is too long + name: "10. Throw error when command is too long", preset: false, presetValue: map[string]interface{}{}, command: []string{"LMOVE", "source10", "destination10", "LEFT", "LEFT", "RIGHT"}, @@ -988,7 +1062,7 @@ func Test_HandleLMOVE(t *testing.T) { expectedError: errors.New(constants.WrongArgsResponse), }, { - // 11. Throw error when WHEREFROM argument is not LEFT/RIGHT + name: "11. Throw error when WHEREFROM argument is not LEFT/RIGHT", preset: false, presetValue: map[string]interface{}{}, command: []string{"LMOVE", "source11", "destination11", "UP", "RIGHT"}, @@ -997,7 +1071,7 @@ func Test_HandleLMOVE(t *testing.T) { expectedError: errors.New("wherefrom and whereto arguments must be either LEFT or RIGHT"), }, { - // 12. Throw error when WHERETO argument is not LEFT/RIGHT + name: "12. Throw error when WHERETO argument is not LEFT/RIGHT", preset: false, presetValue: map[string]interface{}{}, command: []string{"LMOVE", "source11", "destination11", "LEFT", "DOWN"}, @@ -1008,61 +1082,64 @@ func Test_HandleLMOVE(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("LMOVE, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("LMOVE, %d", i)) - if test.preset { - for key, value := range test.presetValue { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValue { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) - } - mockServer.KeyUnlock(ctx, key) - } - } - res, err := handleLMove(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.String() != test.expectedResponse { - t.Errorf("expected \"%s\" response, got \"%s\"", test.expectedResponse, rv.String()) - } - for key, value := range test.expectedValue { - if _, err = mockServer.KeyRLock(ctx, key); err != nil { - t.Error(err) } - list, ok := mockServer.GetValue(ctx, key).([]interface{}) - if !ok { - t.Error("expected value to be list, got another type") + res, err := handleLMove(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return } - expectedList, ok := value.([]interface{}) - if !ok { - t.Error("expected test value to be list, got another type") + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - if len(list) != len(expectedList) { - t.Errorf("expected list length to be %d, got %d", len(expectedList), len(list)) + if rv.String() != test.expectedResponse { + t.Errorf("expected \"%s\" response, got \"%s\"", test.expectedResponse, rv.String()) } - for i := 0; i < len(list); i++ { - if list[i] != expectedList[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, expectedList[i], list[i]) + for key, value := range test.expectedValue { + if _, err = mockServer.KeyRLock(ctx, key); err != nil { + t.Error(err) + } + list, ok := mockServer.GetValue(ctx, key).([]interface{}) + if !ok { + t.Error("expected value to be list, got another type") + } + expectedList, ok := value.([]interface{}) + if !ok { + t.Error("expected test value to be list, got another type") + } + if len(list) != len(expectedList) { + t.Errorf("expected list length to be %d, got %d", len(expectedList), len(list)) } + for i := 0; i < len(list); i++ { + if list[i] != expectedList[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, expectedList[i], list[i]) + } + } + mockServer.KeyRUnlock(ctx, key) } - mockServer.KeyRUnlock(ctx, key) - } + }) } } func Test_HandleLPUSH(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -1071,7 +1148,8 @@ func Test_HandleLPUSH(t *testing.T) { expectedValue []interface{} expectedError error }{ - { // LPUSHX to existing list prepends the element to the list + { + name: "1. LPUSHX to existing list prepends the element to the list", preset: true, key: "LpushKey1", presetValue: []interface{}{"1", "2", "4", "5"}, @@ -1080,7 +1158,8 @@ func Test_HandleLPUSH(t *testing.T) { expectedValue: []interface{}{"value1", "value2", "1", "2", "4", "5"}, expectedError: nil, }, - { // LPUSH on existing list prepends the elements to the list + { + name: "2. LPUSH on existing list prepends the elements to the list", preset: true, key: "LpushKey2", presetValue: []interface{}{"1", "2", "4", "5"}, @@ -1089,7 +1168,8 @@ func Test_HandleLPUSH(t *testing.T) { expectedValue: []interface{}{"value1", "value2", "1", "2", "4", "5"}, expectedError: nil, }, - { // LPUSH on non-existent list creates the list + { + name: "3. LPUSH on non-existent list creates the list", preset: false, key: "LpushKey3", presetValue: nil, @@ -1098,7 +1178,8 @@ func Test_HandleLPUSH(t *testing.T) { expectedValue: []interface{}{"value1", "value2"}, expectedError: nil, }, - { // Command too short + { + name: "4. Command too short", preset: false, key: "LpushKey5", presetValue: nil, @@ -1107,7 +1188,8 @@ func Test_HandleLPUSH(t *testing.T) { expectedValue: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // LPUSHX command returns error on non-existent list + { + name: "5. LPUSHX command returns error on non-existent list", preset: false, key: "LpushKey6", presetValue: nil, @@ -1119,53 +1201,56 @@ func Test_HandleLPUSH(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("LPUSH/LPUSHX, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("LPUSH/LPUSHX, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleLPush(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + if rv.String() != test.expectedResponse { + t.Errorf("expected \"%s\" response, got \"%s\"", test.expectedResponse, rv.String()) + } + if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleLPush(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.String() != test.expectedResponse { - t.Errorf("expected \"%s\" response, got \"%s\"", test.expectedResponse, rv.String()) - } - if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { - t.Error(err) - } - list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) - if !ok { - t.Error("expected value to be list, got another type") - } - if len(list) != len(test.expectedValue) { - t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) - } - for i := 0; i < len(list); i++ { - if list[i] != test.expectedValue[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) - } - } - mockServer.KeyRUnlock(ctx, test.key) + list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) + if !ok { + t.Error("expected value to be list, got another type") + } + if len(list) != len(test.expectedValue) { + t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) + } + for i := 0; i < len(list); i++ { + if list[i] != test.expectedValue[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) + } + } + mockServer.KeyRUnlock(ctx, test.key) + }) } } func Test_HandleRPUSH(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -1174,7 +1259,8 @@ func Test_HandleRPUSH(t *testing.T) { expectedValue []interface{} expectedError error }{ - { // RPUSHX to existing list prepends the element to the list + { + name: "1. RPUSHX to existing list prepends the element to the list", preset: true, key: "RpushKey1", presetValue: []interface{}{"1", "2", "4", "5"}, @@ -1183,7 +1269,8 @@ func Test_HandleRPUSH(t *testing.T) { expectedValue: []interface{}{"1", "2", "4", "5", "value1", "value2"}, expectedError: nil, }, - { // RPUSH on existing list prepends the elements to the list + { + name: "2. RPUSH on existing list prepends the elements to the list", preset: true, key: "RpushKey2", presetValue: []interface{}{"1", "2", "4", "5"}, @@ -1192,7 +1279,8 @@ func Test_HandleRPUSH(t *testing.T) { expectedValue: []interface{}{"1", "2", "4", "5", "value1", "value2"}, expectedError: nil, }, - { // RPUSH on non-existent list creates the list + { + name: "3. RPUSH on non-existent list creates the list", preset: false, key: "RpushKey3", presetValue: nil, @@ -1201,7 +1289,8 @@ func Test_HandleRPUSH(t *testing.T) { expectedValue: []interface{}{"value1", "value2"}, expectedError: nil, }, - { // Command too short + { + name: "4. Command too short", preset: false, key: "RpushKey5", presetValue: nil, @@ -1210,7 +1299,8 @@ func Test_HandleRPUSH(t *testing.T) { expectedValue: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // RPUSHX command returns error on non-existent list + { + name: "5. RPUSHX command returns error on non-existent list", preset: false, key: "RpushKey6", presetValue: nil, @@ -1222,53 +1312,56 @@ func Test_HandleRPUSH(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("RPUSH/RPUSHX, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("RPUSH/RPUSHX, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleRPush(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + if rv.String() != test.expectedResponse { + t.Errorf("expected \"%s\" response, got \"%s\"", test.expectedResponse, rv.String()) + } + if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleRPush(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.String() != test.expectedResponse { - t.Errorf("expected \"%s\" response, got \"%s\"", test.expectedResponse, rv.String()) - } - if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { - t.Error(err) - } - list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) - if !ok { - t.Error("expected value to be list, got another type") - } - if len(list) != len(test.expectedValue) { - t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) - } - for i := 0; i < len(list); i++ { - if list[i] != test.expectedValue[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) - } - } - mockServer.KeyRUnlock(ctx, test.key) + list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) + if !ok { + t.Error("expected value to be list, got another type") + } + if len(list) != len(test.expectedValue) { + t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) + } + for i := 0; i < len(list); i++ { + if list[i] != test.expectedValue[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) + } + } + mockServer.KeyRUnlock(ctx, test.key) + }) } } func Test_HandlePOP(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -1277,7 +1370,8 @@ func Test_HandlePOP(t *testing.T) { expectedValue []interface{} expectedError error }{ - { // LPOP returns last element and removed first element from the list + { + name: "1. LPOP returns last element and removed first element from the list", preset: true, key: "PopKey1", presetValue: []interface{}{"value1", "value2", "value3", "value4"}, @@ -1286,7 +1380,8 @@ func Test_HandlePOP(t *testing.T) { expectedValue: []interface{}{"value2", "value3", "value4"}, expectedError: nil, }, - { // RPOP returns last element and removed last element from the list + { + name: "2. RPOP returns last element and removed last element from the list", preset: true, key: "PopKey2", presetValue: []interface{}{"value1", "value2", "value3", "value4"}, @@ -1295,7 +1390,8 @@ func Test_HandlePOP(t *testing.T) { expectedValue: []interface{}{"value1", "value2", "value3"}, expectedError: nil, }, - { // Command too short + { + name: "3. Command too short", preset: false, key: "PopKey3", presetValue: nil, @@ -1304,7 +1400,8 @@ func Test_HandlePOP(t *testing.T) { expectedValue: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Command too long + { + name: "4. Command too long", preset: false, key: "PopKey4", presetValue: nil, @@ -1313,7 +1410,8 @@ func Test_HandlePOP(t *testing.T) { expectedValue: nil, expectedError: errors.New(constants.WrongArgsResponse), }, - { // Trying to execute LPOP from a non-list item return an error + { + name: "5. Trying to execute LPOP from a non-list item return an error", preset: true, key: "PopKey5", presetValue: "Default value", @@ -1322,7 +1420,8 @@ func Test_HandlePOP(t *testing.T) { expectedValue: nil, expectedError: errors.New("LPOP command on non-list item"), }, - { // Trying to execute RPOP from a non-list item return an error + { + name: "6. Trying to execute RPOP from a non-list item return an error", preset: true, key: "PopKey6", presetValue: "Default value", @@ -1334,47 +1433,49 @@ func Test_HandlePOP(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("LPOP/RPOP, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("LPOP/RPOP, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handlePop(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + if rv.String() != test.expectedResponse { + t.Errorf("expected \"%s\" response, got \"%s\"", test.expectedResponse, rv.String()) + } + if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handlePop(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.String() != test.expectedResponse { - t.Errorf("expected \"%s\" response, got \"%s\"", test.expectedResponse, rv.String()) - } - if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { - t.Error(err) - } - list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) - if !ok { - t.Error("expected value to be list, got another type") - } - if len(list) != len(test.expectedValue) { - t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) - } - for i := 0; i < len(list); i++ { - if list[i] != test.expectedValue[i] { - t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) - } - } - mockServer.KeyRUnlock(ctx, test.key) + list, ok := mockServer.GetValue(ctx, test.key).([]interface{}) + if !ok { + t.Error("expected value to be list, got another type") + } + if len(list) != len(test.expectedValue) { + t.Errorf("expected list length to be %d, got %d", len(test.expectedValue), len(list)) + } + for i := 0; i < len(list); i++ { + if list[i] != test.expectedValue[i] { + t.Errorf("expected element at index %d to be %+v, got %+v", i, test.expectedValue[i], list[i]) + } + } + mockServer.KeyRUnlock(ctx, test.key) + }) } } diff --git a/pkg/modules/set/commant_test.go b/pkg/modules/set/commant_test.go index 3ca92a15..fdd35d54 100644 --- a/pkg/modules/set/commant_test.go +++ b/pkg/modules/set/commant_test.go @@ -41,6 +41,7 @@ func init() { func Test_HandleSADD(t *testing.T) { tests := []struct { + name string preset bool presetValue interface{} key string @@ -49,7 +50,8 @@ func Test_HandleSADD(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Create new set on a non-existent key, return count of added elements + { + name: "1. Create new set on a non-existent key, return count of added elements", preset: false, presetValue: nil, key: "SaddKey1", @@ -58,7 +60,8 @@ func Test_HandleSADD(t *testing.T) { expectedResponse: 4, expectedError: nil, }, - { // 2. Add members to an exiting set, skip members that already exist in the set, return added count. + { + name: "2. Add members to an exiting set, skip members that already exist in the set, return added count.", preset: true, presetValue: set.NewSet([]string{"one", "two", "three", "four"}), key: "SaddKey2", @@ -67,7 +70,8 @@ func Test_HandleSADD(t *testing.T) { expectedResponse: 3, expectedError: nil, }, - { // 3. Throw error when trying to add to a key that does not hold a set + { + name: "3. Throw error when trying to add to a key that does not hold a set", preset: true, presetValue: "Default value", key: "SaddKey3", @@ -75,7 +79,8 @@ func Test_HandleSADD(t *testing.T) { expectedResponse: 0, expectedError: errors.New("value at key SaddKey3 is not a set"), }, - { // 4. Command too short + { + name: "4. Command too short", preset: false, key: "SaddKey4", command: []string{"SADD", "SaddKey4"}, @@ -86,56 +91,59 @@ func Test_HandleSADD(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SADD, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SADD, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleSADD(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + if err != nil { + t.Error(err) + } + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + if rv.Integer() != test.expectedResponse { + t.Errorf("expected integer response %d, got %d", test.expectedResponse, rv.Integer()) + } + if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleSADD(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected integer response %d, got %d", test.expectedResponse, rv.Integer()) - } - if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { - t.Error(err) - } - currSet, ok := mockServer.GetValue(ctx, test.key).(*set.Set) - if !ok { - t.Errorf("expected set value at key \"%s\"", test.key) - } - if currSet.Cardinality() != test.expectedValue.Cardinality() { - t.Errorf("expected resulting cardinality to be %d, got %d", test.expectedValue.Cardinality(), currSet.Cardinality()) - } - for _, member := range currSet.GetAll() { - if !test.expectedValue.Contains(member) { - t.Errorf("could not find member \"%s\" in expected set", member) - } - } - mockServer.KeyRUnlock(ctx, test.key) + currSet, ok := mockServer.GetValue(ctx, test.key).(*set.Set) + if !ok { + t.Errorf("expected set value at key \"%s\"", test.key) + } + if currSet.Cardinality() != test.expectedValue.Cardinality() { + t.Errorf("expected resulting cardinality to be %d, got %d", test.expectedValue.Cardinality(), currSet.Cardinality()) + } + for _, member := range currSet.GetAll() { + if !test.expectedValue.Contains(member) { + t.Errorf("could not find member \"%s\" in expected set", member) + } + } + mockServer.KeyRUnlock(ctx, test.key) + }) } } func Test_HandleSCARD(t *testing.T) { tests := []struct { + name string preset bool presetValue interface{} key string @@ -144,7 +152,8 @@ func Test_HandleSCARD(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Get cardinality of valid set. + { + name: "1. Get cardinality of valid set.", preset: true, presetValue: set.NewSet([]string{"one", "two", "three", "four"}), key: "ScardKey1", @@ -153,7 +162,8 @@ func Test_HandleSCARD(t *testing.T) { expectedResponse: 4, expectedError: nil, }, - { // 2. Return 0 when trying to get cardinality on non-existent key + { + name: "2. Return 0 when trying to get cardinality on non-existent key", preset: false, presetValue: nil, key: "ScardKey2", @@ -162,7 +172,8 @@ func Test_HandleSCARD(t *testing.T) { expectedResponse: 0, expectedError: nil, }, - { // 3. Throw error when trying to get cardinality of a value that is not a set + { + name: "3. Throw error when trying to get cardinality of a value that is not a set", preset: true, presetValue: "Default value", key: "ScardKey3", @@ -170,7 +181,8 @@ func Test_HandleSCARD(t *testing.T) { expectedResponse: 0, expectedError: errors.New("value at key ScardKey3 is not a set"), }, - { // 4. Command too short + { + name: "4. Command too short", preset: false, key: "ScardKey4", command: []string{"SCARD"}, @@ -178,7 +190,8 @@ func Test_HandleSCARD(t *testing.T) { expectedResponse: 0, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 5. Command too long + { + name: "5. Command too long", preset: false, key: "ScardKey5", command: []string{"SCARD", "ScardKey5", "ScardKey5"}, @@ -189,47 +202,51 @@ func Test_HandleSCARD(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SCARD, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SCARD, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleSCARD(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + if err != nil { t.Error(err) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleSCARD(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected integer response %d, got %d", test.expectedResponse, rv.Integer()) - } + if rv.Integer() != test.expectedResponse { + t.Errorf("expected integer response %d, got %d", test.expectedResponse, rv.Integer()) + } + }) } } func Test_HandleSDIFF(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} command []string expectedResponse []string expectedError error }{ - { // 1. Get the difference between 2 sets. + { + name: "1. Get the difference between 2 sets.", preset: true, presetValues: map[string]interface{}{ "SdiffKey1": set.NewSet([]string{"one", "two", "three", "four", "five"}), @@ -239,7 +256,8 @@ func Test_HandleSDIFF(t *testing.T) { expectedResponse: []string{"one", "two"}, expectedError: nil, }, - { // 2. Get the difference between 3 sets. + { + name: "2. Get the difference between 3 sets.", preset: true, presetValues: map[string]interface{}{ "SdiffKey3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), @@ -250,7 +268,8 @@ func Test_HandleSDIFF(t *testing.T) { expectedResponse: []string{"three", "four", "five", "six"}, expectedError: nil, }, - { // 3. Return base set element if base set is the only valid set + { + name: "3. Return base set element if base set is the only valid set", preset: true, presetValues: map[string]interface{}{ "SdiffKey6": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), @@ -261,7 +280,8 @@ func Test_HandleSDIFF(t *testing.T) { expectedResponse: []string{"one", "two", "three", "four", "five", "six", "seven", "eight"}, expectedError: nil, }, - { // 4. Throw error when base set is not a set. + { + name: "4. Throw error when base set is not a set.", preset: true, presetValues: map[string]interface{}{ "SdiffKey9": "Default value", @@ -272,7 +292,8 @@ func Test_HandleSDIFF(t *testing.T) { expectedResponse: nil, expectedError: errors.New("value at key SdiffKey9 is not a set"), }, - { // 5. Throw error when base set is non-existent. + { + name: "5. Throw error when base set is non-existent.", preset: true, presetValues: map[string]interface{}{ "SdiffKey12": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}), @@ -282,7 +303,8 @@ func Test_HandleSDIFF(t *testing.T) { expectedResponse: nil, expectedError: errors.New("key for base set \"non-existent\" does not exist"), }, - { // 6. Command too short + { + name: "6. Command too short", preset: false, command: []string{"SDIFF"}, expectedResponse: []string{}, @@ -291,44 +313,47 @@ func Test_HandleSDIFF(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SDIFF, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SDIFF, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleSDIFF(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + if err != nil { + t.Error(err) + } + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) + } + for _, responseElement := range rv.Array() { + if !slices.Contains(test.expectedResponse, responseElement.String()) { + t.Errorf("could not find response element \"%s\" from expected response array", responseElement.String()) } - mockServer.KeyUnlock(ctx, key) - } - } - res, err := handleSDIFF(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - for _, responseElement := range rv.Array() { - if !slices.Contains(test.expectedResponse, responseElement.String()) { - t.Errorf("could not find response element \"%s\" from expected response array", responseElement.String()) - } - } + } + }) } } func Test_HandleSDIFFSTORE(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} destination string @@ -337,7 +362,8 @@ func Test_HandleSDIFFSTORE(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Get the difference between 2 sets. + { + name: "1. Get the difference between 2 sets.", preset: true, presetValues: map[string]interface{}{ "SdiffStoreKey1": set.NewSet([]string{"one", "two", "three", "four", "five"}), @@ -349,7 +375,8 @@ func Test_HandleSDIFFSTORE(t *testing.T) { expectedResponse: 2, expectedError: nil, }, - { // 2. Get the difference between 3 sets. + { + name: "2. Get the difference between 3 sets.", preset: true, presetValues: map[string]interface{}{ "SdiffStoreKey3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), @@ -362,7 +389,8 @@ func Test_HandleSDIFFSTORE(t *testing.T) { expectedResponse: 4, expectedError: nil, }, - { // 3. Return base set element if base set is the only valid set + { + name: "3. Return base set element if base set is the only valid set", preset: true, presetValues: map[string]interface{}{ "SdiffStoreKey6": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), @@ -375,7 +403,8 @@ func Test_HandleSDIFFSTORE(t *testing.T) { expectedResponse: 8, expectedError: nil, }, - { // 4. Throw error when base set is not a set. + { + name: "4. Throw error when base set is not a set.", preset: true, presetValues: map[string]interface{}{ "SdiffStoreKey9": "Default value", @@ -388,7 +417,8 @@ func Test_HandleSDIFFSTORE(t *testing.T) { expectedResponse: 0, expectedError: errors.New("value at key SdiffStoreKey9 is not a set"), }, - { // 5. Throw error when base set is non-existent. + { + name: "5. Throw error when base set is non-existent.", preset: true, destination: "SdiffStoreDestination5", presetValues: map[string]interface{}{ @@ -400,7 +430,8 @@ func Test_HandleSDIFFSTORE(t *testing.T) { expectedResponse: 0, expectedError: errors.New("key for base set \"non-existent\" does not exist"), }, - { // 6. Command too short + { + name: "6. Command too short", preset: false, command: []string{"SDIFFSTORE", "SdiffStoreDestination6"}, expectedResponse: 0, @@ -409,64 +440,68 @@ func Test_HandleSDIFFSTORE(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SDIFFSTORE, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SDIFFSTORE, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleSDIFFSTORE(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) - } - } - res, err := handleSDIFFSTORE(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response integer %d, got %d", test.expectedResponse, rv.Integer()) - } - if test.expectedValue != nil { - if _, err = mockServer.KeyRLock(ctx, test.destination); err != nil { + return + } + if err != nil { t.Error(err) } - currSet, ok := mockServer.GetValue(ctx, test.destination).(*set.Set) - if !ok { - t.Errorf("expected vaule at key %s to be set, got another type", test.destination) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) + } + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response integer %d, got %d", test.expectedResponse, rv.Integer()) } - for _, elem := range currSet.GetAll() { - if !test.expectedValue.Contains(elem) { - t.Errorf("could not find element %s in the expected values", elem) + if test.expectedValue != nil { + if _, err = mockServer.KeyRLock(ctx, test.destination); err != nil { + t.Error(err) + } + currSet, ok := mockServer.GetValue(ctx, test.destination).(*set.Set) + if !ok { + t.Errorf("expected vaule at key %s to be set, got another type", test.destination) } + for _, elem := range currSet.GetAll() { + if !test.expectedValue.Contains(elem) { + t.Errorf("could not find element %s in the expected values", elem) + } + } + mockServer.KeyRUnlock(ctx, test.destination) } - mockServer.KeyRUnlock(ctx, test.destination) - } + }) } } func Test_HandleSINTER(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} command []string expectedResponse []string expectedError error }{ - { // 1. Get the intersection between 2 sets. + { + name: "1. Get the intersection between 2 sets.", preset: true, presetValues: map[string]interface{}{ "SinterKey1": set.NewSet([]string{"one", "two", "three", "four", "five"}), @@ -476,7 +511,8 @@ func Test_HandleSINTER(t *testing.T) { expectedResponse: []string{"three", "four", "five"}, expectedError: nil, }, - { // 2. Get the intersection between 3 sets. + { + name: "2. Get the intersection between 3 sets.", preset: true, presetValues: map[string]interface{}{ "SinterKey3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), @@ -487,7 +523,8 @@ func Test_HandleSINTER(t *testing.T) { expectedResponse: []string{"one", "eight"}, expectedError: nil, }, - { // 3. Throw an error if any of the provided keys are not sets + { + name: "3. Throw an error if any of the provided keys are not sets", preset: true, presetValues: map[string]interface{}{ "SinterKey6": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), @@ -498,7 +535,8 @@ func Test_HandleSINTER(t *testing.T) { expectedResponse: nil, expectedError: errors.New("value at key SinterKey7 is not a set"), }, - { // 4. Throw error when base set is not a set. + { + name: "4. Throw error when base set is not a set.", preset: true, presetValues: map[string]interface{}{ "SinterKey9": "Default value", @@ -509,7 +547,8 @@ func Test_HandleSINTER(t *testing.T) { expectedResponse: nil, expectedError: errors.New("value at key SinterKey9 is not a set"), }, - { // 5. If any of the keys does not exist, return an empty array. + { + name: "5. If any of the keys does not exist, return an empty array.", preset: true, presetValues: map[string]interface{}{ "SinterKey12": set.NewSet([]string{"one", "two", "thirty-six", "twelve", "eleven"}), @@ -519,7 +558,8 @@ func Test_HandleSINTER(t *testing.T) { expectedResponse: []string{}, expectedError: nil, }, - { // 6. Command too short + { + name: "6. Command too short", preset: false, command: []string{"SINTER"}, expectedResponse: []string{}, @@ -528,51 +568,55 @@ func Test_HandleSINTER(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SINTER, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SINTER, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleSINTER(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) - } - } - res, err := handleSINTER(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - for _, responseElement := range rv.Array() { - if !slices.Contains(test.expectedResponse, responseElement.String()) { - t.Errorf("could not find response element \"%s\" from expected response array", responseElement.String()) - } - } + return + } + if err != nil { + t.Error(err) + } + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) + } + for _, responseElement := range rv.Array() { + if !slices.Contains(test.expectedResponse, responseElement.String()) { + t.Errorf("could not find response element \"%s\" from expected response array", responseElement.String()) + } + } + }) } } func Test_HandleSINTERCARD(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} command []string expectedResponse int expectedError error }{ - { // 1. Get the full intersect cardinality between 2 sets. + { + name: "1. Get the full intersect cardinality between 2 sets.", preset: true, presetValues: map[string]interface{}{ "SinterCardKey1": set.NewSet([]string{"one", "two", "three", "four", "five"}), @@ -582,7 +626,8 @@ func Test_HandleSINTERCARD(t *testing.T) { expectedResponse: 3, expectedError: nil, }, - { // 2. Get an intersect cardinality between 2 sets with a limit + { + name: "2. Get an intersect cardinality between 2 sets with a limit", preset: true, presetValues: map[string]interface{}{ "SinterCardKey3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"}), @@ -592,7 +637,8 @@ func Test_HandleSINTERCARD(t *testing.T) { expectedResponse: 3, expectedError: nil, }, - { // 3. Get the full intersect cardinality between 3 sets. + { + name: "3. Get the full intersect cardinality between 3 sets.", preset: true, presetValues: map[string]interface{}{ "SinterCardKey5": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), @@ -603,7 +649,8 @@ func Test_HandleSINTERCARD(t *testing.T) { expectedResponse: 2, expectedError: nil, }, - { // 4. Get the intersection of 3 sets with a limit + { + name: "4. Get the intersection of 3 sets with a limit", preset: true, presetValues: map[string]interface{}{ "SinterCardKey8": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), @@ -614,7 +661,8 @@ func Test_HandleSINTERCARD(t *testing.T) { expectedResponse: 2, expectedError: nil, }, - { // 5. Return 0 if any of the keys does not exist + { + name: "5. Return 0 if any of the keys does not exist", preset: true, presetValues: map[string]interface{}{ "SinterCardKey11": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), @@ -625,7 +673,8 @@ func Test_HandleSINTERCARD(t *testing.T) { expectedResponse: 0, expectedError: nil, }, - { // 6. Throw error when one of the keys is not a valid set. + { + name: "6. Throw error when one of the keys is not a valid set.", preset: true, presetValues: map[string]interface{}{ "SinterCardKey14": "Default value", @@ -636,7 +685,8 @@ func Test_HandleSINTERCARD(t *testing.T) { expectedResponse: 0, expectedError: errors.New("value at key SinterCardKey14 is not a set"), }, - { // 7. Command too short + { + name: "7. Command too short", preset: false, command: []string{"SINTERCARD"}, expectedResponse: 0, @@ -645,42 +695,45 @@ func Test_HandleSINTERCARD(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SINTERCARD, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SINTERCARD, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleSINTERCARD(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) - } - } - res, err := handleSINTERCARD(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response integer %d, got %d", test.expectedResponse, rv.Integer()) - } + return + } + if err != nil { + t.Error(err) + } + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) + } + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response integer %d, got %d", test.expectedResponse, rv.Integer()) + } + }) } } func Test_HandleSINTERSTORE(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} destination string @@ -689,7 +742,8 @@ func Test_HandleSINTERSTORE(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Get the intersection between 2 sets and store it at the destination. + { + name: "1. Get the intersection between 2 sets and store it at the destination.", preset: true, presetValues: map[string]interface{}{ "SinterStoreKey1": set.NewSet([]string{"one", "two", "three", "four", "five"}), @@ -701,7 +755,8 @@ func Test_HandleSINTERSTORE(t *testing.T) { expectedResponse: 3, expectedError: nil, }, - { // 2. Get the intersection between 3 sets and store it at the destination key. + { + name: "2. Get the intersection between 3 sets and store it at the destination key.", preset: true, presetValues: map[string]interface{}{ "SinterStoreKey3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), @@ -714,7 +769,8 @@ func Test_HandleSINTERSTORE(t *testing.T) { expectedResponse: 2, expectedError: nil, }, - { // 3. Throw error when any of the keys is not a set + { + name: "3. Throw error when any of the keys is not a set", preset: true, presetValues: map[string]interface{}{ "SinterStoreKey6": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), @@ -727,7 +783,8 @@ func Test_HandleSINTERSTORE(t *testing.T) { expectedResponse: 0, expectedError: errors.New("value at key SinterStoreKey7 is not a set"), }, - { // 4. Throw error when base set is not a set. + { + name: "4. Throw error when base set is not a set.", preset: true, presetValues: map[string]interface{}{ "SinterStoreKey9": "Default value", @@ -740,7 +797,8 @@ func Test_HandleSINTERSTORE(t *testing.T) { expectedResponse: 0, expectedError: errors.New("value at key SinterStoreKey9 is not a set"), }, - { // 5. Return an empty intersection if one of the keys does not exist. + { + name: "5. Return an empty intersection if one of the keys does not exist.", preset: true, destination: "SinterStoreDestination5", presetValues: map[string]interface{}{ @@ -752,7 +810,8 @@ func Test_HandleSINTERSTORE(t *testing.T) { expectedResponse: 0, expectedError: nil, }, - { // 6. Command too short + { + name: "6. Command too short", preset: false, command: []string{"SINTERSTORE", "SinterStoreDestination6"}, expectedResponse: 0, @@ -761,57 +820,60 @@ func Test_HandleSINTERSTORE(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SINTERSTORE, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SINTERSTORE, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleSINTERSTORE(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) - } - } - res, err := handleSINTERSTORE(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response integer %d, got %d", test.expectedResponse, rv.Integer()) - } - if test.expectedValue != nil { - if _, err = mockServer.KeyRLock(ctx, test.destination); err != nil { + return + } + if err != nil { t.Error(err) } - currSet, ok := mockServer.GetValue(ctx, test.destination).(*set.Set) - if !ok { - t.Errorf("expected vaule at key %s to be set, got another type", test.destination) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - for _, elem := range currSet.GetAll() { - if !test.expectedValue.Contains(elem) { - t.Errorf("could not find element %s in the expected values", elem) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response integer %d, got %d", test.expectedResponse, rv.Integer()) + } + if test.expectedValue != nil { + if _, err = mockServer.KeyRLock(ctx, test.destination); err != nil { + t.Error(err) + } + currSet, ok := mockServer.GetValue(ctx, test.destination).(*set.Set) + if !ok { + t.Errorf("expected vaule at key %s to be set, got another type", test.destination) + } + for _, elem := range currSet.GetAll() { + if !test.expectedValue.Contains(elem) { + t.Errorf("could not find element %s in the expected values", elem) + } } + mockServer.KeyRUnlock(ctx, test.destination) } - mockServer.KeyRUnlock(ctx, test.destination) - } + }) } } func Test_HandleSISMEMBER(t *testing.T) { tests := []struct { + name string preset bool presetValue interface{} key string @@ -819,7 +881,8 @@ func Test_HandleSISMEMBER(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Return 1 when element is a member of the set + { + name: "1. Return 1 when element is a member of the set", preset: true, presetValue: set.NewSet([]string{"one", "two", "three", "four"}), key: "SIsMemberKey1", @@ -827,7 +890,8 @@ func Test_HandleSISMEMBER(t *testing.T) { expectedResponse: 1, expectedError: nil, }, - { // 2. Return 0 when element is not a member of the set + { + name: "2. Return 0 when element is not a member of the set", preset: true, presetValue: set.NewSet([]string{"one", "two", "three", "four"}), key: "SIsMemberKey2", @@ -835,7 +899,8 @@ func Test_HandleSISMEMBER(t *testing.T) { expectedResponse: 0, expectedError: nil, }, - { // 3. Throw error when trying to assert membership when the key does not hold a valid set + { + name: "3. Throw error when trying to assert membership when the key does not hold a valid set", preset: true, presetValue: "Default value", key: "SIsMemberKey3", @@ -843,14 +908,16 @@ func Test_HandleSISMEMBER(t *testing.T) { expectedResponse: 0, expectedError: errors.New("value at key SIsMemberKey3 is not a set"), }, - { // 4. Command too short + { + name: "4. Command too short", preset: false, key: "SIsMemberKey4", command: []string{"SISMEMBER", "SIsMemberKey4"}, expectedResponse: 0, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 5. Command too long + { + name: "5. Command too long", preset: false, key: "SIsMemberKey5", command: []string{"SISMEMBER", "SIsMemberKey5", "one", "two", "three"}, @@ -860,40 +927,43 @@ func Test_HandleSISMEMBER(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SISMEMBER, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SISMEMBER, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleSISMEMBER(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + if err != nil { t.Error(err) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleSISMEMBER(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected integer response %d, got %d", test.expectedResponse, rv.Integer()) - } + if rv.Integer() != test.expectedResponse { + t.Errorf("expected integer response %d, got %d", test.expectedResponse, rv.Integer()) + } + }) } } func Test_HandleSMEMBERS(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -901,7 +971,8 @@ func Test_HandleSMEMBERS(t *testing.T) { expectedResponse []string expectedError error }{ - { // 1. Return all the members of the set. + { + name: "1. Return all the members of the set.", preset: true, key: "SmembersKey1", presetValue: set.NewSet([]string{"one", "two", "three", "four", "five"}), @@ -909,7 +980,8 @@ func Test_HandleSMEMBERS(t *testing.T) { expectedResponse: []string{"one", "two", "three", "four", "five"}, expectedError: nil, }, - { // 2. If the key does not exist, return an empty array. + { + name: "2. If the key does not exist, return an empty array.", preset: false, key: "SmembersKey2", presetValue: nil, @@ -917,7 +989,8 @@ func Test_HandleSMEMBERS(t *testing.T) { expectedResponse: []string{}, expectedError: nil, }, - { // 3. Throw error when the provided key is not a set. + { + name: "3. Throw error when the provided key is not a set.", preset: true, key: "SmembersKey3", presetValue: "Default value", @@ -925,13 +998,15 @@ func Test_HandleSMEMBERS(t *testing.T) { expectedResponse: nil, expectedError: errors.New("value at key SmembersKey3 is not a set"), }, - { // 4. Command too short + { + name: "4. Command too short", preset: false, command: []string{"SMEMBERS"}, expectedResponse: []string{}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 5. Command too long + { + name: "5. Command too long", preset: false, command: []string{"SMEMBERS", "SmembersKey5", "SmembersKey6"}, expectedResponse: []string{}, @@ -940,45 +1015,48 @@ func Test_HandleSMEMBERS(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SMEMBERS, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SMEMBERS, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleSMEMBERS(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + if err != nil { t.Error(err) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleSMEMBERS(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if len(rv.Array()) != len(test.expectedResponse) { - t.Errorf("expected response array of length %d, got %d", len(test.expectedResponse), len(rv.Array())) - } - for _, responseElement := range rv.Array() { - if !slices.Contains(test.expectedResponse, responseElement.String()) { - t.Errorf("could not find response element \"%s\" from expected response array", responseElement.String()) - } - } + if len(rv.Array()) != len(test.expectedResponse) { + t.Errorf("expected response array of length %d, got %d", len(test.expectedResponse), len(rv.Array())) + } + for _, responseElement := range rv.Array() { + if !slices.Contains(test.expectedResponse, responseElement.String()) { + t.Errorf("could not find response element \"%s\" from expected response array", responseElement.String()) + } + } + }) } } func Test_HandleSMISMEMBER(t *testing.T) { tests := []struct { + name string preset bool presetValue interface{} key string @@ -991,6 +1069,7 @@ func Test_HandleSMISMEMBER(t *testing.T) { // Return 1 for present and 0 for absent // The placement of the membership status flag should me consistent with the order the elements // are in within the original command + name: "1. Return set membership status for multiple elements", preset: true, presetValue: set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven"}), key: "SmismemberKey1", @@ -998,7 +1077,8 @@ func Test_HandleSMISMEMBER(t *testing.T) { expectedResponse: []int{1, 1, 1, 1, 0, 0, 1}, expectedError: nil, }, - { // 2. If the set key does not exist, return an array of zeroes as long as the list of members + { + name: "2. If the set key does not exist, return an array of zeroes as long as the list of members", preset: false, presetValue: nil, key: "SmismemberKey2", @@ -1006,7 +1086,8 @@ func Test_HandleSMISMEMBER(t *testing.T) { expectedResponse: []int{0, 0, 0, 0}, expectedError: nil, }, - { // 3. Throw error when trying to assert membership when the key does not hold a valid set + { + name: "3. Throw error when trying to assert membership when the key does not hold a valid set", preset: true, presetValue: "Default value", key: "SmismemberKey3", @@ -1014,7 +1095,8 @@ func Test_HandleSMISMEMBER(t *testing.T) { expectedResponse: nil, expectedError: errors.New("value at key SmismemberKey3 is not a set"), }, - { // 4. Command too short + { + name: "4. Command too short", preset: false, key: "SmismemberKey4", command: []string{"SMISMEMBER", "SmismemberKey4"}, @@ -1024,43 +1106,46 @@ func Test_HandleSMISMEMBER(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SMISMEMBER, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SMISMEMBER, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleSMISMEMBER(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + if err != nil { t.Error(err) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleSMISMEMBER(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - responseArray := rv.Array() - for i := 0; i < len(responseArray); i++ { - if responseArray[i].Integer() != test.expectedResponse[i] { - t.Errorf("expected integer %d at index %d, got %d", test.expectedResponse[i], i, responseArray[i].Integer()) - } - } + responseArray := rv.Array() + for i := 0; i < len(responseArray); i++ { + if responseArray[i].Integer() != test.expectedResponse[i] { + t.Errorf("expected integer %d at index %d, got %d", test.expectedResponse[i], i, responseArray[i].Integer()) + } + } + }) } } func Test_HandleSMOVE(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} command []string @@ -1068,7 +1153,8 @@ func Test_HandleSMOVE(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Return 1 after a successful move of a member from source set to destination set + { + name: "1. Return 1 after a successful move of a member from source set to destination set", preset: true, presetValues: map[string]interface{}{ "SmoveSource1": set.NewSet([]string{"one", "two", "three", "four"}), @@ -1082,7 +1168,8 @@ func Test_HandleSMOVE(t *testing.T) { expectedResponse: 1, expectedError: nil, }, - { // 2. Return 0 when trying to move a member from source set to destination set when it doesn't exist in source + { + name: "2. Return 0 when trying to move a member from source set to destination set when it doesn't exist in source", preset: true, presetValues: map[string]interface{}{ "SmoveSource2": set.NewSet([]string{"one", "two", "three", "four", "five"}), @@ -1096,7 +1183,8 @@ func Test_HandleSMOVE(t *testing.T) { expectedResponse: 0, expectedError: nil, }, - { // 3. Return error when the source key is not a set + { + name: "3. Return error when the source key is not a set", preset: true, presetValues: map[string]interface{}{ "SmoveSource3": "Default value", @@ -1110,7 +1198,8 @@ func Test_HandleSMOVE(t *testing.T) { expectedResponse: 0, expectedError: errors.New("source is not a set"), }, - { // 4. Return error when the destination key is not a set + { + name: "4. Return error when the destination key is not a set", preset: true, presetValues: map[string]interface{}{ "SmoveSource4": set.NewSet([]string{"one", "two", "three", "four", "five"}), @@ -1124,12 +1213,14 @@ func Test_HandleSMOVE(t *testing.T) { expectedResponse: 0, expectedError: errors.New("destination is not a set"), }, - { // 5. Command too short + { + name: "5. Command too short", preset: false, command: []string{"SMOVE", "SmoveSource5", "SmoveSource6"}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 6. Command too long + { + name: "6. Command too long", preset: false, command: []string{"SMOVE", "SmoveSource5", "SmoveSource6", "member1", "member2"}, expectedError: errors.New(constants.WrongArgsResponse), @@ -1137,64 +1228,67 @@ func Test_HandleSMOVE(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SMOVE, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SMOVE, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleSMOVE(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) - } - } - res, err := handleSMOVE(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response integer %d, got %d", test.expectedResponse, rv.Integer()) - } - for key, value := range test.expectedValues { - expectedSet, ok := value.(*set.Set) - if !ok { - t.Errorf("expected value at \"%s\" should be a set", key) + return } - if _, err = mockServer.KeyRLock(ctx, key); err != nil { - t.Error(key) + if err != nil { + t.Error(err) } - currSet, ok := mockServer.GetValue(ctx, key).(*set.Set) - if !ok { - t.Errorf("expected set \"%s\" to be a set, got another type", key) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - if expectedSet.Cardinality() != currSet.Cardinality() { - t.Errorf("expected set to have cardinaltity %d, got %d", expectedSet.Cardinality(), currSet.Cardinality()) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response integer %d, got %d", test.expectedResponse, rv.Integer()) } - for _, element := range expectedSet.GetAll() { - if !currSet.Contains(element) { - t.Errorf("could not find element \"%s\" in the expected set", element) + for key, value := range test.expectedValues { + expectedSet, ok := value.(*set.Set) + if !ok { + t.Errorf("expected value at \"%s\" should be a set", key) + } + if _, err = mockServer.KeyRLock(ctx, key); err != nil { + t.Error(key) + } + currSet, ok := mockServer.GetValue(ctx, key).(*set.Set) + if !ok { + t.Errorf("expected set \"%s\" to be a set, got another type", key) } + if expectedSet.Cardinality() != currSet.Cardinality() { + t.Errorf("expected set to have cardinaltity %d, got %d", expectedSet.Cardinality(), currSet.Cardinality()) + } + for _, element := range expectedSet.GetAll() { + if !currSet.Contains(element) { + t.Errorf("could not find element \"%s\" in the expected set", element) + } + } + mockServer.KeyRUnlock(ctx, key) } - mockServer.KeyRUnlock(ctx, key) - } + }) } } func Test_HandleSPOP(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -1203,7 +1297,8 @@ func Test_HandleSPOP(t *testing.T) { expectedResponse []string expectedError error }{ - { // 1. Return multiple popped elements and modify the set + { + name: "1. Return multiple popped elements and modify the set", preset: true, key: "SpopKey1", presetValue: set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), @@ -1212,7 +1307,8 @@ func Test_HandleSPOP(t *testing.T) { expectedResponse: []string{"one", "two", "three", "four", "five", "six", "seven", "eight"}, expectedError: nil, }, - { // 2. Return error when the source key is not a set + { + name: "2. Return error when the source key is not a set", preset: true, key: "SpopKey2", presetValue: "Default value", @@ -1221,17 +1317,20 @@ func Test_HandleSPOP(t *testing.T) { expectedResponse: []string{}, expectedError: errors.New("value at SpopKey2 is not a set"), }, - { // 3. Command too short + { + name: "3. Command too short", preset: false, command: []string{"SPOP"}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 4. Command too long + { + name: "4. Command too long", preset: false, command: []string{"SPOP", "SpopSource5", "SpopSource6", "member1", "member2"}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 5. Throw error when count is not an integer + { + name: "5. Throw error when count is not an integer", preset: false, command: []string{"SPOP", "SpopKey1", "count"}, expectedError: errors.New("count must be an integer"), @@ -1239,60 +1338,63 @@ func Test_HandleSPOP(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SPOP, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SPOP, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleSPOP(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + if err != nil { + t.Error(err) + } + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + // 1. Check if the response array members are all included in test.expectedResponse. + for _, element := range rv.Array() { + if !slices.Contains(test.expectedResponse, element.String()) { + t.Errorf("expected response array does not contain element \"%s\"", element.String()) + } + } + // 2. Fetch the set and check if its cardinality is what we expect. + if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleSPOP(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - // 1. Check if the response array members are all included in test.expectedResponse. - for _, element := range rv.Array() { - if !slices.Contains(test.expectedResponse, element.String()) { - t.Errorf("expected response array does not contain element \"%s\"", element.String()) - } - } - // 2. Fetch the set and check if its cardinality is what we expect. - if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { - t.Error(err) - } - currSet, ok := mockServer.GetValue(ctx, test.key).(*set.Set) - if !ok { - t.Errorf("expected value at key \"%s\" to be a set, got another type", test.key) - } - if currSet.Cardinality() != test.expectedValue { - t.Errorf("expected cardinality of final set to be %d, got %d", test.expectedValue, currSet.Cardinality()) - } - // 3. Check if all the popped elements we received are no longer in the set. - for _, element := range rv.Array() { - if currSet.Contains(element.String()) { - t.Errorf("expected element \"%s\" to not be in set but it was found", element.String()) - } - } + currSet, ok := mockServer.GetValue(ctx, test.key).(*set.Set) + if !ok { + t.Errorf("expected value at key \"%s\" to be a set, got another type", test.key) + } + if currSet.Cardinality() != test.expectedValue { + t.Errorf("expected cardinality of final set to be %d, got %d", test.expectedValue, currSet.Cardinality()) + } + // 3. Check if all the popped elements we received are no longer in the set. + for _, element := range rv.Array() { + if currSet.Contains(element.String()) { + t.Errorf("expected element \"%s\" to not be in set but it was found", element.String()) + } + } + }) } } func Test_HandleSRANDMEMBER(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -1302,8 +1404,10 @@ func Test_HandleSRANDMEMBER(t *testing.T) { expectedResponse []string expectedError error }{ - { // 1. Return multiple random elements without removing them + { + // 1. Return multiple random elements without removing them // Count is positive, do not allow repeated elements + name: "1. Return multiple random elements without removing them", preset: true, key: "SRandMemberKey1", presetValue: set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), @@ -1316,6 +1420,7 @@ func Test_HandleSRANDMEMBER(t *testing.T) { { // 2. Return multiple random elements without removing them // Count is negative, so allow repeated numbers + name: "2. Return multiple random elements without removing them", preset: true, key: "SRandMemberKey2", presetValue: set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), @@ -1325,7 +1430,8 @@ func Test_HandleSRANDMEMBER(t *testing.T) { expectedResponse: []string{"one", "two", "three", "four", "five", "six", "seven", "eight"}, expectedError: nil, }, - { // 3. Return error when the source key is not a set + { + name: "3. Return error when the source key is not a set", preset: true, key: "SRandMemberKey3", presetValue: "Default value", @@ -1334,17 +1440,20 @@ func Test_HandleSRANDMEMBER(t *testing.T) { expectedResponse: []string{}, expectedError: errors.New("value at SRandMemberKey3 is not a set"), }, - { // 4. Command too short + { + name: "4. Command too short", preset: false, command: []string{"SRANDMEMBER"}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 5. Command too long + { + name: "5. Command too long", preset: false, command: []string{"SRANDMEMBER", "SRandMemberSource5", "SRandMemberSource6", "member1", "member2"}, expectedError: errors.New(constants.WrongArgsResponse), }, - { // 6. Throw error when count is not an integer + { + name: "6. Throw error when count is not an integer", preset: false, command: []string{"SRANDMEMBER", "SRandMemberKey1", "count"}, expectedError: errors.New("count must be an integer"), @@ -1352,71 +1461,74 @@ func Test_HandleSRANDMEMBER(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SRANDMEMBER, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SRANDMEMBER, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleSRANDMEMBER(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return + } + if err != nil { t.Error(err) } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) + } + // 1. Check if the response array members are all included in test.expectedResponse. + for _, element := range rv.Array() { + if !slices.Contains(test.expectedResponse, element.String()) { + t.Errorf("expected response array does not contain element \"%s\"", element.String()) + } + } + // 2. Fetch the set and check if its cardinality is what we expect. + if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleSRANDMEMBER(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - // 1. Check if the response array members are all included in test.expectedResponse. - for _, element := range rv.Array() { - if !slices.Contains(test.expectedResponse, element.String()) { - t.Errorf("expected response array does not contain element \"%s\"", element.String()) - } - } - // 2. Fetch the set and check if its cardinality is what we expect. - if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { - t.Error(err) - } - currSet, ok := mockServer.GetValue(ctx, test.key).(*set.Set) - if !ok { - t.Errorf("expected value at key \"%s\" to be a set, got another type", test.key) - } - if currSet.Cardinality() != test.expectedValue { - t.Errorf("expected cardinality of final set to be %d, got %d", test.expectedValue, currSet.Cardinality()) - } - // 3. Check if all the returned elements we received are still in the set. - for _, element := range rv.Array() { - if !currSet.Contains(element.String()) { - t.Errorf("expected element \"%s\" to be in set but it was not found", element.String()) - } - } - // 4. If allowRepeat is false, check that all the elements make a valid set - if !test.allowRepeat { - var elems []string - for _, e := range rv.Array() { - elems = append(elems, e.String()) - } - s := set.NewSet(elems) - if s.Cardinality() != len(elems) { - t.Errorf("expected non-repeating elements for random elements at key \"%s\"", test.key) - } - } + currSet, ok := mockServer.GetValue(ctx, test.key).(*set.Set) + if !ok { + t.Errorf("expected value at key \"%s\" to be a set, got another type", test.key) + } + if currSet.Cardinality() != test.expectedValue { + t.Errorf("expected cardinality of final set to be %d, got %d", test.expectedValue, currSet.Cardinality()) + } + // 3. Check if all the returned elements we received are still in the set. + for _, element := range rv.Array() { + if !currSet.Contains(element.String()) { + t.Errorf("expected element \"%s\" to be in set but it was not found", element.String()) + } + } + // 4. If allowRepeat is false, check that all the elements make a valid set + if !test.allowRepeat { + var elems []string + for _, e := range rv.Array() { + elems = append(elems, e.String()) + } + s := set.NewSet(elems) + if s.Cardinality() != len(elems) { + t.Errorf("expected non-repeating elements for random elements at key \"%s\"", test.key) + } + } + }) } } func Test_HandleSREM(t *testing.T) { tests := []struct { + name string preset bool key string presetValue interface{} @@ -1425,7 +1537,8 @@ func Test_HandleSREM(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Remove multiple elements and return the number of elements removed + { + name: "1. Remove multiple elements and return the number of elements removed", preset: true, key: "SremKey1", presetValue: set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), @@ -1434,7 +1547,8 @@ func Test_HandleSREM(t *testing.T) { expectedResponse: 3, expectedError: nil, }, - { // 2. If key does not exist, return 0 + { + name: "2. If key does not exist, return 0", preset: false, key: "SremKey2", presetValue: nil, @@ -1443,7 +1557,8 @@ func Test_HandleSREM(t *testing.T) { expectedResponse: 0, expectedError: nil, }, - { // 3. Return error when the source key is not a set + { + name: "3. Return error when the source key is not a set", preset: true, key: "SremKey3", presetValue: "Default value", @@ -1452,7 +1567,8 @@ func Test_HandleSREM(t *testing.T) { expectedResponse: 0, expectedError: errors.New("value at key SremKey3 is not a set"), }, - { // 4. Command too short + { + name: "4. Command too short", preset: false, command: []string{"SREM", "SremKey"}, expectedError: errors.New(constants.WrongArgsResponse), @@ -1460,62 +1576,66 @@ func Test_HandleSREM(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SREM, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SREM, %d", i)) - if test.preset { - if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { - t.Error(err) + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, test.key) + } + res, err := handleSREM(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) + } + return } - if err := mockServer.SetValue(ctx, test.key, test.presetValue); err != nil { + if err != nil { t.Error(err) } - mockServer.KeyUnlock(ctx, test.key) - } - res, err := handleSREM(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected integer response %d, got %d", test.expectedResponse, rv.Integer()) - } - if test.expectedValue != nil { - if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { t.Error(err) } - currSet, ok := mockServer.GetValue(ctx, test.key).(*set.Set) - if !ok { - t.Errorf("expected value at key \"%s\" to be a set, got another type", test.key) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected integer response %d, got %d", test.expectedResponse, rv.Integer()) } - for _, element := range currSet.GetAll() { - if !test.expectedValue.Contains(element) { - t.Errorf("element \"%s\" not found in expected set values but found in set", element) + if test.expectedValue != nil { + if _, err = mockServer.KeyRLock(ctx, test.key); err != nil { + t.Error(err) + } + currSet, ok := mockServer.GetValue(ctx, test.key).(*set.Set) + if !ok { + t.Errorf("expected value at key \"%s\" to be a set, got another type", test.key) + } + for _, element := range currSet.GetAll() { + if !test.expectedValue.Contains(element) { + t.Errorf("element \"%s\" not found in expected set values but found in set", element) + } } + mockServer.KeyRUnlock(ctx, test.key) } - mockServer.KeyRUnlock(ctx, test.key) - } + }) } } func Test_HandleSUNION(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} command []string expectedResponse []string expectedError error }{ - { // 1. Get the union between 2 sets. + { + name: "1. Get the union between 2 sets.", preset: true, presetValues: map[string]interface{}{ "SunionKey1": set.NewSet([]string{"one", "two", "three", "four", "five"}), @@ -1525,7 +1645,8 @@ func Test_HandleSUNION(t *testing.T) { expectedResponse: []string{"one", "two", "three", "four", "five", "six", "seven", "eight"}, expectedError: nil, }, - { // 2. Get the union between 3 sets. + { + name: "2. Get the union between 3 sets.", preset: true, presetValues: map[string]interface{}{ "SunionKey3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), @@ -1539,7 +1660,8 @@ func Test_HandleSUNION(t *testing.T) { }, expectedError: nil, }, - { // 3. Throw an error if any of the provided keys are not sets + { + name: "3. Throw an error if any of the provided keys are not sets", preset: true, presetValues: map[string]interface{}{ "SunionKey6": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), @@ -1550,7 +1672,8 @@ func Test_HandleSUNION(t *testing.T) { expectedResponse: nil, expectedError: errors.New("value at key SunionKey7 is not a set"), }, - { // 4. Throw error any of the keys does not hold a set. + { + name: "4. Throw error any of the keys does not hold a set.", preset: true, presetValues: map[string]interface{}{ "SunionKey9": "Default value", @@ -1561,7 +1684,8 @@ func Test_HandleSUNION(t *testing.T) { expectedResponse: nil, expectedError: errors.New("value at key SunionKey9 is not a set"), }, - { // 6. Command too short + { + name: "6. Command too short", preset: false, command: []string{"SUNION"}, expectedResponse: []string{}, @@ -1570,44 +1694,47 @@ func Test_HandleSUNION(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SUNION, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SUNION, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleSUNION(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) - } - } - res, err := handleSUNION(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - for _, responseElement := range rv.Array() { - if !slices.Contains(test.expectedResponse, responseElement.String()) { - t.Errorf("could not find response element \"%s\" from expected response array", responseElement.String()) - } - } + return + } + if err != nil { + t.Error(err) + } + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) + } + for _, responseElement := range rv.Array() { + if !slices.Contains(test.expectedResponse, responseElement.String()) { + t.Errorf("could not find response element \"%s\" from expected response array", responseElement.String()) + } + } + }) } } func Test_HandleSUNIONSTORE(t *testing.T) { tests := []struct { + name string preset bool presetValues map[string]interface{} destination string @@ -1616,7 +1743,8 @@ func Test_HandleSUNIONSTORE(t *testing.T) { expectedResponse int expectedError error }{ - { // 1. Get the intersection between 2 sets and store it at the destination. + { + name: "1. Get the intersection between 2 sets and store it at the destination.", preset: true, presetValues: map[string]interface{}{ "SunionStoreKey1": set.NewSet([]string{"one", "two", "three", "four", "five"}), @@ -1628,7 +1756,8 @@ func Test_HandleSUNIONSTORE(t *testing.T) { expectedResponse: 8, expectedError: nil, }, - { // 2. Get the intersection between 3 sets and store it at the destination key. + { + name: "2. Get the intersection between 3 sets and store it at the destination key.", preset: true, presetValues: map[string]interface{}{ "SunionStoreKey3": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), @@ -1644,7 +1773,8 @@ func Test_HandleSUNIONSTORE(t *testing.T) { expectedResponse: 13, expectedError: nil, }, - { // 3. Throw error when any of the keys is not a set + { + name: "3. Throw error when any of the keys is not a set", preset: true, presetValues: map[string]interface{}{ "SunionStoreKey6": set.NewSet([]string{"one", "two", "three", "four", "five", "six", "seven", "eight"}), @@ -1657,7 +1787,8 @@ func Test_HandleSUNIONSTORE(t *testing.T) { expectedResponse: 0, expectedError: errors.New("value at key SunionStoreKey7 is not a set"), }, - { // 5. Command too short + { + name: "5. Command too short", preset: false, command: []string{"SUNIONSTORE", "SunionStoreDestination6"}, expectedResponse: 0, @@ -1666,51 +1797,53 @@ func Test_HandleSUNIONSTORE(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SUNIONSTORE, %d", i)) + t.Run(test.name, func(t *testing.T) { + ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("SUNIONSTORE, %d", i)) - if test.preset { - for key, value := range test.presetValues { - if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { - t.Error(err) + if test.preset { + for key, value := range test.presetValues { + if _, err := mockServer.CreateKeyAndLock(ctx, key); err != nil { + t.Error(err) + } + if err := mockServer.SetValue(ctx, key, value); err != nil { + t.Error(err) + } + mockServer.KeyUnlock(ctx, key) } - if err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) + } + res, err := handleSUNIONSTORE(ctx, test.command, mockServer, nil) + if test.expectedError != nil { + if err.Error() != test.expectedError.Error() { + t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) } - mockServer.KeyUnlock(ctx, key) - } - } - res, err := handleSUNIONSTORE(ctx, test.command, mockServer, nil) - if test.expectedError != nil { - if err.Error() != test.expectedError.Error() { - t.Errorf("expected error \"%s\", got \"%s\"", test.expectedError.Error(), err.Error()) - } - continue - } - if err != nil { - t.Error(err) - } - rd := resp.NewReader(bytes.NewBuffer(res)) - rv, _, err := rd.ReadValue() - if err != nil { - t.Error(err) - } - if rv.Integer() != test.expectedResponse { - t.Errorf("expected response integer %d, got %d", test.expectedResponse, rv.Integer()) - } - if test.expectedValue != nil { - if _, err = mockServer.KeyRLock(ctx, test.destination); err != nil { + return + } + if err != nil { t.Error(err) } - currSet, ok := mockServer.GetValue(ctx, test.destination).(*set.Set) - if !ok { - t.Errorf("expected vaule at key %s to be set, got another type", test.destination) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - for _, elem := range currSet.GetAll() { - if !test.expectedValue.Contains(elem) { - t.Errorf("could not find element %s in the expected values", elem) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response integer %d, got %d", test.expectedResponse, rv.Integer()) + } + if test.expectedValue != nil { + if _, err = mockServer.KeyRLock(ctx, test.destination); err != nil { + t.Error(err) + } + currSet, ok := mockServer.GetValue(ctx, test.destination).(*set.Set) + if !ok { + t.Errorf("expected vaule at key %s to be set, got another type", test.destination) + } + for _, elem := range currSet.GetAll() { + if !test.expectedValue.Contains(elem) { + t.Errorf("could not find element %s in the expected values", elem) + } } + mockServer.KeyRUnlock(ctx, test.destination) } - mockServer.KeyRUnlock(ctx, test.destination) - } + }) } } From a605a7bd146c68d94e01b93568f40726b3f13fad Mon Sep 17 00:00:00 2001 From: Kelvin Mwinuka Date: Sat, 6 Apr 2024 02:30:38 +0800 Subject: [PATCH 6/8] Added discord badge to README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 832a3ef7..33bd7bd9 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,10 @@ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
[![Go Reference](https://pkg.go.dev/badge/github.com/echovault/echovault.svg)](https://pkg.go.dev/github.com/echovault/echovault) +
+[![Discord](https://img.shields.io/discord/1211815152291414037?style=flat&label=Discord&color=%235865F2) +](https://discord.gg/aasBFwDm) +

echovault_logo From 44b55c6fd8f7f07c13eed01e705487414a38d71f Mon Sep 17 00:00:00 2001 From: Kelvin Mwinuka Date: Sat, 6 Apr 2024 02:35:11 +0800 Subject: [PATCH 7/8] Add waitgroup to init server starter in pubsub commands module --- pkg/modules/pubsub/commands_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/modules/pubsub/commands_test.go b/pkg/modules/pubsub/commands_test.go index 23b2695b..e1d42fd3 100644 --- a/pkg/modules/pubsub/commands_test.go +++ b/pkg/modules/pubsub/commands_test.go @@ -25,6 +25,7 @@ import ( "github.com/tidwall/resp" "net" "slices" + "sync" "testing" "time" ) @@ -38,9 +39,14 @@ var port uint16 = 7490 func init() { mockServer = setUpServer(bindAddr, port) pubsub = mockServer.GetPubSub().(*internal_pubsub.PubSub) + + wg := sync.WaitGroup{} + wg.Add(1) go func() { + wg.Add(1) mockServer.Start() }() + wg.Wait() } func setUpServer(bindAddr string, port uint16) *echovault.EchoVault { From 64bbda620534b9c9e758fe61546c8a99bbe8d28d Mon Sep 17 00:00:00 2001 From: Kelvin Mwinuka Date: Sat, 6 Apr 2024 02:37:44 +0800 Subject: [PATCH 8/8] wg.Done intead of wg.Add in goroutine that starts server in pubusub test module init function --- coverage/coverage.out | 450 ++++++++++++++-------------- pkg/modules/pubsub/commands_test.go | 2 +- 2 files changed, 226 insertions(+), 226 deletions(-) diff --git a/coverage/coverage.out b/coverage/coverage.out index 203fd0b9..a95df820 100644 --- a/coverage/coverage.out +++ b/coverage/coverage.out @@ -1108,6 +1108,231 @@ github.com/echovault/echovault/pkg/modules/acl/commands.go:578.62,580.7 1 1 github.com/echovault/echovault/pkg/modules/acl/commands.go:589.62,591.7 1 1 github.com/echovault/echovault/pkg/modules/acl/commands.go:603.62,605.7 1 0 github.com/echovault/echovault/pkg/modules/acl/commands.go:614.62,616.7 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:30.105,32.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:32.16,34.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:36.2,38.33 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:38.33,41.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:43.2,43.52 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:43.52,45.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:46.2,48.63 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:48.63,50.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:52.2,52.57 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:55.110,57.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:57.16,59.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:61.2,64.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:64.9,66.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:68.2,68.33 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:68.33,70.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:72.2,72.52 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:72.52,74.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:75.2,78.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:78.9,80.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:82.2,82.40 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:82.40,84.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:86.2,86.57 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:89.110,91.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:91.16,93.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:95.2,99.24 4 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:99.24,101.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:103.2,103.33 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:103.33,105.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:107.2,107.52 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:107.52,109.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:110.2,113.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:113.9,115.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:118.2,118.40 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:118.40,120.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:123.2,123.51 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:123.51,125.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:127.2,130.15 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:130.15,132.43 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:132.43,135.4 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:136.3,136.20 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:140.2,140.18 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:140.18,142.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:147.2,151.17 4 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:151.17,153.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:155.2,155.13 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:155.13,158.18 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:158.18,160.4 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:160.9,162.4 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:165.2,165.19 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:168.108,170.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:170.16,172.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:174.2,177.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:177.9,179.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:181.2,181.33 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:181.33,183.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:185.2,185.51 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:185.51,187.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:188.2,191.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:191.9,193.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:195.2,195.40 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:195.40,197.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:199.2,200.55 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:200.55,202.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:204.2,204.42 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:207.109,209.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:209.16,211.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:213.2,217.24 4 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:217.24,219.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:221.2,221.30 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:221.30,223.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:225.2,225.33 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:225.33,227.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:229.2,229.51 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:229.51,231.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:232.2,235.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:235.9,237.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:239.2,239.40 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:239.40,241.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:243.2,243.34 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:243.34,244.64 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:244.64,246.4 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:247.3,247.43 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:250.2,250.66 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:250.66,252.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:253.2,253.42 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:256.108,258.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:258.16,260.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:262.2,266.9 4 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:266.9,268.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:270.2,272.33 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:272.33,274.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:276.2,276.51 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:276.51,278.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:279.2,282.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:282.9,284.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:286.2,286.9 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:287.10,287.10 0 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:289.17,291.34 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:291.34,292.26 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:292.26,293.10 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:295.4,295.43 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:295.43,298.5 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:300.17,302.39 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:302.39,303.26 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:303.26,304.10 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:306.4,306.43 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:306.43,309.5 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:313.2,313.61 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:313.61,315.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:317.2,317.55 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:317.55,319.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:321.2,321.42 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:324.109,326.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:326.16,328.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:330.2,335.116 5 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:335.116,337.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:339.2,339.75 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:339.75,341.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:343.2,343.54 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:343.54,345.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:346.2,349.16 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:349.16,351.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:352.2,357.33 4 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:357.33,359.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:361.2,361.19 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:362.14,364.24 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:364.24,366.4 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:366.9,366.32 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:366.32,368.4 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:369.15,371.24 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:371.24,373.4 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:373.9,373.32 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:373.32,375.4 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:378.2,378.16 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:378.16,380.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:382.2,382.42 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:385.106,387.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:387.16,389.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:391.2,393.31 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:393.31,395.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:397.2,399.33 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:399.33,400.34 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:401.17,402.61 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:403.11,404.62 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:404.62,406.5 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:407.4,407.68 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:407.68,409.5 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:411.8,412.52 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:412.52,414.4 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:416.2,421.9 4 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:421.9,423.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:425.2,425.73 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:425.73,427.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:428.2,428.42 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:431.109,433.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:433.16,435.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:437.2,441.31 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:441.31,443.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:445.2,445.33 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:445.33,446.34 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:447.17,448.61 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:449.11,450.62 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:450.62,452.5 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:453.4,454.68 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:454.68,456.5 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:458.8,459.52 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:459.52,461.4 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:462.3,462.35 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:465.2,469.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:469.9,471.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:473.2,473.73 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:473.73,475.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:476.2,476.42 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:479.104,481.16 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:481.16,483.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:485.2,487.33 2 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:487.33,489.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:491.2,491.51 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:491.51,493.3 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:494.2,497.9 3 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:497.9,499.3 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:501.2,501.33 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:502.10,503.60 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:503.60,505.4 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:506.3,506.54 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:507.14,508.70 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:508.70,510.4 1 0 +github.com/echovault/echovault/pkg/modules/list/commands.go:511.3,511.64 1 1 +github.com/echovault/echovault/pkg/modules/list/commands.go:515.33,635.2 1 0 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:22.51,23.18 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:23.18,25.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:26.2,26.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:29.49,30.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:30.19,32.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:33.2,33.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:36.50,37.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:37.19,39.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:40.2,40.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:43.52,44.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:44.19,46.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:47.2,47.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:50.52,51.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:51.19,53.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:54.2,54.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:57.50,58.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:58.19,60.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:61.2,61.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:64.51,65.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:65.19,67.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:68.2,68.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:71.50,72.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:72.19,74.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:75.2,75.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:78.51,79.18 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:79.18,81.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:82.2,82.30 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:85.51,86.19 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:86.19,88.3 1 1 +github.com/echovault/echovault/pkg/modules/list/key_funcs.go:89.2,89.38 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:26.108,27.18 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:28.10,29.54 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:30.9,31.34 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:32.9,33.72 1 1 +github.com/echovault/echovault/pkg/modules/connection/commands.go:37.33,45.60 1 0 +github.com/echovault/echovault/pkg/modules/connection/commands.go:45.60,47.5 1 0 github.com/echovault/echovault/pkg/modules/admin/commands.go:29.115,35.29 4 1 github.com/echovault/echovault/pkg/modules/admin/commands.go:35.29,36.54 1 1 github.com/echovault/echovault/pkg/modules/admin/commands.go:36.54,42.42 4 1 @@ -1184,12 +1409,6 @@ github.com/echovault/echovault/pkg/modules/admin/commands.go:284.60,286.5 1 0 github.com/echovault/echovault/pkg/modules/admin/commands.go:287.113,288.47 1 0 github.com/echovault/echovault/pkg/modules/admin/commands.go:288.47,290.6 1 0 github.com/echovault/echovault/pkg/modules/admin/commands.go:291.5,291.45 1 0 -github.com/echovault/echovault/pkg/modules/connection/commands.go:26.108,27.18 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:28.10,29.54 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:30.9,31.34 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:32.9,33.72 1 1 -github.com/echovault/echovault/pkg/modules/connection/commands.go:37.33,45.60 1 0 -github.com/echovault/echovault/pkg/modules/connection/commands.go:45.60,47.5 1 0 github.com/echovault/echovault/pkg/modules/generic/commands.go:36.104,38.16 2 1 github.com/echovault/echovault/pkg/modules/generic/commands.go:38.16,40.3 1 1 github.com/echovault/echovault/pkg/modules/generic/commands.go:42.2,48.16 6 1 @@ -1704,225 +1923,6 @@ github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:99.2,99.22 1 1 github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:102.50,103.18 1 1 github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:103.18,105.3 1 1 github.com/echovault/echovault/pkg/modules/hash/key_funcs.go:106.2,106.22 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:30.105,32.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:32.16,34.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:36.2,38.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:38.33,41.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:43.2,43.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:43.52,45.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:46.2,48.63 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:48.63,50.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:52.2,52.57 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:55.110,57.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:57.16,59.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:61.2,64.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:64.9,66.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:68.2,68.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:68.33,70.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:72.2,72.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:72.52,74.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:75.2,78.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:78.9,80.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:82.2,82.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:82.40,84.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:86.2,86.57 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:89.110,91.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:91.16,93.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:95.2,99.24 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:99.24,101.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:103.2,103.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:103.33,105.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:107.2,107.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:107.52,109.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:110.2,113.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:113.9,115.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:118.2,118.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:118.40,120.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:123.2,123.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:123.51,125.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:127.2,130.15 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:130.15,132.43 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:132.43,135.4 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:136.3,136.20 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:140.2,140.18 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:140.18,142.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:147.2,151.17 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:151.17,153.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:155.2,155.13 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:155.13,158.18 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:158.18,160.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:160.9,162.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:165.2,165.19 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:168.108,170.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:170.16,172.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:174.2,177.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:177.9,179.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:181.2,181.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:181.33,183.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:185.2,185.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:185.51,187.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:188.2,191.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:191.9,193.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:195.2,195.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:195.40,197.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:199.2,200.55 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:200.55,202.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:204.2,204.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:207.109,209.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:209.16,211.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:213.2,217.24 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:217.24,219.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:221.2,221.30 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:221.30,223.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:225.2,225.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:225.33,227.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:229.2,229.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:229.51,231.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:232.2,235.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:235.9,237.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:239.2,239.40 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:239.40,241.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:243.2,243.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:243.34,244.64 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:244.64,246.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:247.3,247.43 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:250.2,250.66 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:250.66,252.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:253.2,253.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:256.108,258.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:258.16,260.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:262.2,266.9 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:266.9,268.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:270.2,272.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:272.33,274.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:276.2,276.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:276.51,278.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:279.2,282.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:282.9,284.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:286.2,286.9 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:287.10,287.10 0 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:289.17,291.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:291.34,292.26 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:292.26,293.10 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:295.4,295.43 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:295.43,298.5 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:300.17,302.39 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:302.39,303.26 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:303.26,304.10 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:306.4,306.43 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:306.43,309.5 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:313.2,313.61 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:313.61,315.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:317.2,317.55 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:317.55,319.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:321.2,321.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:324.109,326.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:326.16,328.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:330.2,335.116 5 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:335.116,337.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:339.2,339.75 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:339.75,341.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:343.2,343.54 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:343.54,345.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:346.2,349.16 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:349.16,351.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:352.2,357.33 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:357.33,359.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:361.2,361.19 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:362.14,364.24 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:364.24,366.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:366.9,366.32 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:366.32,368.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:369.15,371.24 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:371.24,373.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:373.9,373.32 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:373.32,375.4 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:378.2,378.16 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:378.16,380.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:382.2,382.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:385.106,387.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:387.16,389.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:391.2,393.31 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:393.31,395.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:397.2,399.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:399.33,400.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:401.17,402.61 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:403.11,404.62 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:404.62,406.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:407.4,407.68 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:407.68,409.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:411.8,412.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:412.52,414.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:416.2,421.9 4 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:421.9,423.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:425.2,425.73 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:425.73,427.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:428.2,428.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:431.109,433.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:433.16,435.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:437.2,441.31 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:441.31,443.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:445.2,445.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:445.33,446.34 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:447.17,448.61 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:449.11,450.62 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:450.62,452.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:453.4,454.68 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:454.68,456.5 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:458.8,459.52 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:459.52,461.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:462.3,462.35 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:465.2,469.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:469.9,471.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:473.2,473.73 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:473.73,475.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:476.2,476.42 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:479.104,481.16 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:481.16,483.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:485.2,487.33 2 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:487.33,489.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:491.2,491.51 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:491.51,493.3 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:494.2,497.9 3 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:497.9,499.3 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:501.2,501.33 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:502.10,503.60 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:503.60,505.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:506.3,506.54 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:507.14,508.70 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:508.70,510.4 1 0 -github.com/echovault/echovault/pkg/modules/list/commands.go:511.3,511.64 1 1 -github.com/echovault/echovault/pkg/modules/list/commands.go:515.33,635.2 1 0 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:22.51,23.18 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:23.18,25.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:26.2,26.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:29.49,30.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:30.19,32.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:33.2,33.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:36.50,37.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:37.19,39.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:40.2,40.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:43.52,44.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:44.19,46.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:47.2,47.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:50.52,51.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:51.19,53.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:54.2,54.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:57.50,58.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:58.19,60.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:61.2,61.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:64.51,65.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:65.19,67.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:68.2,68.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:71.50,72.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:72.19,74.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:75.2,75.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:78.51,79.18 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:79.18,81.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:82.2,82.30 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:85.51,86.19 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:86.19,88.3 1 1 -github.com/echovault/echovault/pkg/modules/list/key_funcs.go:89.2,89.38 1 1 github.com/echovault/echovault/pkg/modules/pubsub/commands.go:28.113,30.9 2 1 github.com/echovault/echovault/pkg/modules/pubsub/commands.go:30.9,32.3 1 0 github.com/echovault/echovault/pkg/modules/pubsub/commands.go:34.2,36.24 2 1 diff --git a/pkg/modules/pubsub/commands_test.go b/pkg/modules/pubsub/commands_test.go index e1d42fd3..03ca8a73 100644 --- a/pkg/modules/pubsub/commands_test.go +++ b/pkg/modules/pubsub/commands_test.go @@ -43,7 +43,7 @@ func init() { wg := sync.WaitGroup{} wg.Add(1) go func() { - wg.Add(1) + wg.Done() mockServer.Start() }() wg.Wait()