diff --git a/coverage/coverage.out b/coverage/coverage.out index 7920f91..a293d55 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 b37681b..bf8ed36 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) - } - mockServer.KeyUnlock(ctx, key) } - } - 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()) - } - 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 + 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()) } - for i := 0; i < len(expected); i++ { - if element.Array()[i].String() != expected[i] { + return + } + 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] { + 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()) - } - 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 { + 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) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - 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 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) } + 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 err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) - } - mockServer.KeyUnlock(ctx, key) - } - } - 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()) - } - 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] { - return false + 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) } - 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 { + 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()) + } + return + } + if 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) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - if !set.Equals(expectedSortedSet) { - t.Errorf("expected sorted set at key \"%s\" %+v, got %+v", key, expectedSortedSet, set) + 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()) + } } - } + 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 err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) - } - mockServer.KeyUnlock(ctx, key) - } - } - 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()) - } - 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] { - return false + 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) } - 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 { + 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()) + } + return + } + if 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) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - if !set.Equals(expectedSortedSet) { - t.Errorf("expected sorted set at key \"%s\" %+v, got %+v", key, expectedSortedSet, set) + 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()) + } } - } + 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]) + 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 + } + 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()) } - 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 err := mockServer.SetValue(ctx, test.key, test.presetValue); 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()) - } - 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 + if test.preset { + if _, err := mockServer.CreateKeyAndLock(ctx, test.key); err != nil { + t.Error(err) } - for i := 0; i < len(expected); i++ { - if element.Array()[i].String() != expected[i] { + if err := mockServer.SetValue(ctx, test.key, test.presetValue); 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()) + } + return + } + 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] { + 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 err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) - } - mockServer.KeyUnlock(ctx, key) - } - } - 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()) - } - 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) + 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 := 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()) + } + 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 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 err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) - } - mockServer.KeyUnlock(ctx, key) - } - } - 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()) - } - 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) + 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 := 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()) + } + 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_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 err := mockServer.SetValue(ctx, key, value); err != nil { - t.Error(err) - } - mockServer.KeyUnlock(ctx, key) - } - } - 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()) - } - 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) + 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 := 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()) + } + 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_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,12 +2691,14 @@ 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), @@ -2539,64 +2706,68 @@ func Test_HandleZREMRANGEBYLEX(t *testing.T) { } for i, test := range tests { - ctx := context.WithValue(context.Background(), "test_name", fmt.Sprintf("ZREMRANGEBYLEX, %d", i)) + 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) - } - } - 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) - } - 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) + 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()) + } + 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) - } - mockServer.KeyUnlock(ctx, key) } - } - 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()) - } - 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 + 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()) } - for i := 0; i < len(expected); i++ { - if element.Array()[i].String() != expected[i] { + return + } + 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] { + 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()) - } - 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 { + 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) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - if !set.Equals(test.expectedValue) { - t.Errorf("expected sorted set %+v, got %+v", test.expectedValue, set) + if rv.Integer() != test.expectedResponse { + t.Errorf("expected response integer %d, got %d", test.expectedResponse, rv.Integer()) } - mockServer.KeyRUnlock(ctx, test.destination) - } + 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) + } + }) } } 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) - } - mockServer.KeyUnlock(ctx, key) } - } - 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()) - } - 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 + 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()) } - for i := 0; i < len(expected); i++ { - if element.Array()[i].String() != expected[i] { + return + } + 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] { + 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()) - } - 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 { + 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) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - 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 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) } + 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) - } - mockServer.KeyUnlock(ctx, key) } - } - 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()) - } - 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 + 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()) } - for i := 0; i < len(expected); i++ { - if element.Array()[i].String() != expected[i] { + return + } + 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] { + 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()) - } - 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 { + 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) + rd := resp.NewReader(bytes.NewBuffer(res)) + rv, _, err := rd.ReadValue() + if err != nil { + t.Error(err) } - 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 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) } + 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) - } + }) } }