| 1 | // Copyright (c) 2019-2026 Alexander Medvednikov. All rights reserved. |
| 2 | // Use of this source code is governed by an MIT license |
| 3 | // that can be found in the LICENSE file. |
| 4 | module s3 |
| 5 | |
| 6 | // Captured from a real ListObjectsV2 response (S3-compatible endpoint), |
| 7 | // trimmed to the fields we parse. |
| 8 | const list_response_xml = '<?xml version="1.0" encoding="UTF-8"?> |
| 9 | <ListBucketResult> |
| 10 | <Name>test-bucket</Name> |
| 11 | <Prefix>foo/</Prefix> |
| 12 | <KeyCount>2</KeyCount> |
| 13 | <MaxKeys>1000</MaxKeys> |
| 14 | <IsTruncated>false</IsTruncated> |
| 15 | <Contents> |
| 16 | <Key>foo/a.txt</Key> |
| 17 | <Size>10</Size> |
| 18 | <ETag>"d41d8cd98f00b204e9800998ecf8427e"</ETag> |
| 19 | <LastModified>2024-01-15T00:00:00.000Z</LastModified> |
| 20 | <StorageClass>STANDARD</StorageClass> |
| 21 | </Contents> |
| 22 | <Contents> |
| 23 | <Key>foo/b.txt</Key> |
| 24 | <Size>20</Size> |
| 25 | <ETag>"9b8b80d22b1d56a3f9b2c25d6e3e74c5"</ETag> |
| 26 | <LastModified>2024-01-16T00:00:00.000Z</LastModified> |
| 27 | </Contents> |
| 28 | </ListBucketResult>' |
| 29 | |
| 30 | fn test_parse_list_response_basic() { |
| 31 | r := parse_list_response(list_response_xml) or { panic(err) } |
| 32 | assert r.name == 'test-bucket' |
| 33 | assert r.prefix == 'foo/' |
| 34 | assert r.key_count == 2 |
| 35 | assert !r.is_truncated |
| 36 | assert r.objects.len == 2 |
| 37 | assert r.objects[0].key == 'foo/a.txt' |
| 38 | assert r.objects[0].size == 10 |
| 39 | assert r.objects[0].etag == 'd41d8cd98f00b204e9800998ecf8427e' |
| 40 | assert r.objects[1].key == 'foo/b.txt' |
| 41 | } |
| 42 | |
| 43 | fn test_parse_list_response_truncated() { |
| 44 | body := '<?xml version="1.0"?><ListBucketResult><Name>b</Name><IsTruncated>true</IsTruncated><NextContinuationToken>opaqueToken==</NextContinuationToken><KeyCount>1</KeyCount><Contents><Key>only.txt</Key><Size>1</Size><ETag>"abc"</ETag></Contents></ListBucketResult>' |
| 45 | r := parse_list_response(body) or { panic(err) } |
| 46 | assert r.is_truncated |
| 47 | assert r.next_continuation_token == 'opaqueToken==' |
| 48 | } |
| 49 | |
| 50 | fn test_parse_list_response_common_prefixes() { |
| 51 | body := '<?xml version="1.0"?><ListBucketResult><Name>b</Name><Delimiter>/</Delimiter><CommonPrefixes><Prefix>folder1/</Prefix></CommonPrefixes><CommonPrefixes><Prefix>folder2/</Prefix></CommonPrefixes><KeyCount>0</KeyCount></ListBucketResult>' |
| 52 | r := parse_list_response(body) or { panic(err) } |
| 53 | assert r.delimiter == '/' |
| 54 | assert r.common_prefixes.len == 2 |
| 55 | assert r.common_prefixes[0].prefix == 'folder1/' |
| 56 | assert r.common_prefixes[1].prefix == 'folder2/' |
| 57 | } |
| 58 | |