Merge branch '8784-dir-listings'
[arvados.git] / sdk / go / blockdigest / blockdigest_test.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: Apache-2.0
4
5 package blockdigest
6
7 import (
8         "fmt"
9         "runtime"
10         "strings"
11         "testing"
12 )
13
14 func getStackTrace() string {
15         buf := make([]byte, 1000)
16         bytes_written := runtime.Stack(buf, false)
17         return "Stack Trace:\n" + string(buf[:bytes_written])
18 }
19
20 func expectEqual(t *testing.T, actual interface{}, expected interface{}) {
21         if actual != expected {
22                 t.Fatalf("Expected %v but received %v instead. %s",
23                         expected,
24                         actual,
25                         getStackTrace())
26         }
27 }
28
29 func expectStringSlicesEqual(t *testing.T, actual []string, expected []string) {
30         if len(actual) != len(expected) {
31                 t.Fatalf("Expected %v (length %d), but received %v (length %d) instead. %s", expected, len(expected), actual, len(actual), getStackTrace())
32         }
33         for i := range actual {
34                 if actual[i] != expected[i] {
35                         t.Fatalf("Expected %v but received %v instead (first disagreement at position %d). %s", expected, actual, i, getStackTrace())
36                 }
37         }
38 }
39
40 func expectValidDigestString(t *testing.T, s string) {
41         bd, err := FromString(s)
42         if err != nil {
43                 t.Fatalf("Expected %s to produce a valid BlockDigest but instead got error: %v", s, err)
44         }
45
46         expected := strings.ToLower(s)
47
48         if expected != bd.String() {
49                 t.Fatalf("Expected %s to be returned by FromString(%s).String() but instead we received %s", expected, s, bd.String())
50         }
51 }
52
53 func expectInvalidDigestString(t *testing.T, s string) {
54         _, err := FromString(s)
55         if err == nil {
56                 t.Fatalf("Expected %s to be an invalid BlockDigest, but did not receive an error", s)
57         }
58 }
59
60 func expectBlockLocator(t *testing.T, actual BlockLocator, expected BlockLocator) {
61         expectEqual(t, actual.Digest, expected.Digest)
62         expectEqual(t, actual.Size, expected.Size)
63         expectStringSlicesEqual(t, actual.Hints, expected.Hints)
64 }
65
66 func expectLocatorPatternMatch(t *testing.T, s string) {
67         if !LocatorPattern.MatchString(s) {
68                 t.Fatalf("Expected \"%s\" to match locator pattern but it did not.",
69                         s)
70         }
71 }
72
73 func expectLocatorPatternFail(t *testing.T, s string) {
74         if LocatorPattern.MatchString(s) {
75                 t.Fatalf("Expected \"%s\" to fail locator pattern but it passed.",
76                         s)
77         }
78 }
79
80 func TestValidDigestStrings(t *testing.T) {
81         expectValidDigestString(t, "01234567890123456789abcdefabcdef")
82         expectValidDigestString(t, "01234567890123456789ABCDEFABCDEF")
83         expectValidDigestString(t, "01234567890123456789AbCdEfaBcDeF")
84 }
85
86 func TestInvalidDigestStrings(t *testing.T) {
87         expectInvalidDigestString(t, "01234567890123456789abcdefabcdeg")
88         expectInvalidDigestString(t, "01234567890123456789abcdefabcde")
89         expectInvalidDigestString(t, "01234567890123456789abcdefabcdefa")
90         expectInvalidDigestString(t, "g1234567890123456789abcdefabcdef")
91 }
92
93 func TestBlockDigestWorksAsMapKey(t *testing.T) {
94         m := make(map[BlockDigest]int)
95         bd, err := FromString("01234567890123456789abcdefabcdef")
96         if err != nil {
97                 t.Fatalf("Unexpected error during FromString for block: %v", err)
98         }
99         m[bd] = 5
100 }
101
102 func TestBlockDigestGetsPrettyPrintedByPrintf(t *testing.T) {
103         input := "01234567890123456789abcdefabcdef"
104         fromString, err := FromString(input)
105         if err != nil {
106                 t.Fatalf("Unexpected error during FromString: %v", err)
107         }
108         prettyPrinted := fmt.Sprintf("%v", fromString)
109         if prettyPrinted != input {
110                 t.Fatalf("Expected blockDigest produced from \"%s\" to be printed as "+
111                         "\"%s\", but instead it was printed as %s",
112                         input, input, prettyPrinted)
113         }
114 }
115
116 func TestBlockDigestGetsPrettyPrintedByPrintfInNestedStructs(t *testing.T) {
117         input, err := FromString("01234567890123456789abcdefabcdef")
118         if err != nil {
119                 t.Fatalf("Unexpected error during FromString for block: %v", err)
120         }
121         value := 42
122         nested := struct {
123                 // Fun trivia fact: If this field was called "digest" instead of
124                 // "Digest", then it would not be exported and String() would
125                 // never get called on it and our output would look very
126                 // different.
127                 Digest BlockDigest
128                 value  int
129         }{
130                 input,
131                 value,
132         }
133         prettyPrinted := fmt.Sprintf("%+v", nested)
134         expected := fmt.Sprintf("{Digest:%s value:%d}", input, value)
135         if prettyPrinted != expected {
136                 t.Fatalf("Expected blockDigest produced from \"%s\" to be printed as "+
137                         "\"%s\", but instead it was printed as %s",
138                         input, expected, prettyPrinted)
139         }
140 }
141
142 func TestLocatorPatternBasic(t *testing.T) {
143         expectLocatorPatternMatch(t, "12345678901234567890123456789012+12345")
144         expectLocatorPatternMatch(t, "A2345678901234abcdefababdeffdfdf+12345")
145         expectLocatorPatternMatch(t, "12345678901234567890123456789012+12345+A1")
146         expectLocatorPatternMatch(t,
147                 "12345678901234567890123456789012+12345+A1+B123wxyz@_-")
148         expectLocatorPatternMatch(t,
149                 "12345678901234567890123456789012+12345+A1+B123wxyz@_-+C@")
150         expectLocatorPatternMatch(t, "12345678901234567890123456789012+12345+A")
151         expectLocatorPatternMatch(t, "12345678901234567890123456789012+12345+A1+B")
152         expectLocatorPatternMatch(t, "12345678901234567890123456789012+12345+A+B2")
153
154         expectLocatorPatternFail(t, "12345678901234567890123456789012")
155         expectLocatorPatternFail(t, "12345678901234567890123456789012+")
156         expectLocatorPatternFail(t, "12345678901234567890123456789012+12345+")
157         expectLocatorPatternFail(t, "1234567890123456789012345678901+12345")
158         expectLocatorPatternFail(t, "123456789012345678901234567890123+12345")
159         expectLocatorPatternFail(t, "g2345678901234abcdefababdeffdfdf+12345")
160         expectLocatorPatternFail(t, "12345678901234567890123456789012+12345 ")
161         expectLocatorPatternFail(t, "12345678901234567890123456789012+12345+1")
162         expectLocatorPatternFail(t, "12345678901234567890123456789012+12345+1A")
163         expectLocatorPatternFail(t, "12345678901234567890123456789012+12345+a1")
164         expectLocatorPatternFail(t, "12345678901234567890123456789012+12345+A1+")
165
166 }
167
168 func TestParseBlockLocatorSimple(t *testing.T) {
169         b, err := ParseBlockLocator("365f83f5f808896ec834c8b595288735+2310+K@qr1hi+Af0c9a66381f3b028677411926f0be1c6282fe67c@542b5ddf")
170         if err != nil {
171                 t.Fatalf("Unexpected error parsing block locator: %v", err)
172         }
173         d, err := FromString("365f83f5f808896ec834c8b595288735")
174         if err != nil {
175                 t.Fatalf("Unexpected error during FromString for block: %v", err)
176         }
177         expectBlockLocator(t, b, BlockLocator{Digest: d,
178                 Size: 2310,
179                 Hints: []string{"K@qr1hi",
180                         "Af0c9a66381f3b028677411926f0be1c6282fe67c@542b5ddf"}})
181 }