1
2
3
4
5
6
7
8
9 package main
10
11 import (
12 "archive/zip"
13 "crypto/sha256"
14 "encoding/json"
15 "fmt"
16 "io/ioutil"
17 "log"
18 "os"
19 "path"
20 "path/filepath"
21
22 "go.mongodb.org/mongo-driver/bson"
23 )
24
25 const dataDir = "testdata/bson-corpus/"
26
27 type validityTestCase struct {
28 Description string `json:"description"`
29 CanonicalExtJSON string `json:"canonical_extjson"`
30 RelaxedExtJSON *string `json:"relaxed_extjson"`
31 DegenerateExtJSON *string `json:"degenerate_extjson"`
32 ConvertedExtJSON *string `json:"converted_extjson"`
33 }
34
35 func findJSONFilesInDir(dir string) ([]string, error) {
36 files := make([]string, 0)
37
38 entries, err := ioutil.ReadDir(dir)
39 if err != nil {
40 return nil, err
41 }
42
43 for _, entry := range entries {
44 if entry.IsDir() || path.Ext(entry.Name()) != ".json" {
45 continue
46 }
47
48 files = append(files, entry.Name())
49 }
50
51 return files, nil
52 }
53
54
55 func jsonToNative(ej, ejType, testDesc string) (bson.D, error) {
56 var doc bson.D
57 if err := bson.UnmarshalExtJSON([]byte(ej), ejType != "relaxed", &doc); err != nil {
58 return nil, fmt.Errorf("%s: decoding %s extended JSON: %w", testDesc, ejType, err)
59 }
60 return doc, nil
61 }
62
63
64 func jsonToBytes(ej, ejType, testDesc string) ([]byte, error) {
65 native, err := jsonToNative(ej, ejType, testDesc)
66 if err != nil {
67 return nil, err
68 }
69
70 b, err := bson.Marshal(native)
71 if err != nil {
72 return nil, fmt.Errorf("%s: encoding %s BSON: %w", testDesc, ejType, err)
73 }
74
75 return b, nil
76 }
77
78
79 func seedExtJSON(zw *zip.Writer, extJSON string, extJSONType string, desc string) {
80 jbytes, err := jsonToBytes(extJSON, extJSONType, desc)
81 if err != nil {
82 log.Fatalf("failed to convert JSON to bytes: %v", err)
83 }
84
85
86
87 zipFile := fmt.Sprintf("%x", sha256.Sum256(jbytes))
88
89 f, err := zw.Create(zipFile)
90 if err != nil {
91 log.Fatalf("error creating zip file: %v", err)
92 }
93
94 _, err = f.Write(jbytes)
95 if err != nil {
96 log.Fatalf("failed to write file: %s into zip file: %v", zipFile, err)
97 }
98 }
99
100
101
102 func seedTestCase(zw *zip.Writer, tcase []*validityTestCase) {
103 for _, vtc := range tcase {
104 seedExtJSON(zw, vtc.CanonicalExtJSON, "canonical", vtc.Description)
105
106
107 if vtc.RelaxedExtJSON != nil {
108 seedExtJSON(zw, *vtc.RelaxedExtJSON, "relaxed", vtc.Description)
109 }
110
111
112 if vtc.DegenerateExtJSON != nil {
113 seedExtJSON(zw, *vtc.DegenerateExtJSON, "degenerate", vtc.Description)
114 }
115
116
117 if vtc.ConvertedExtJSON != nil {
118 seedExtJSON(zw, *vtc.ConvertedExtJSON, "converted", vtc.Description)
119 }
120 }
121 }
122
123
124
125 func seedBSONCorpus(zw *zip.Writer) {
126 fileNames, err := findJSONFilesInDir(dataDir)
127 if err != nil {
128 log.Fatalf("failed to find JSON files in directory %q: %v", dataDir, err)
129 }
130
131 for _, fileName := range fileNames {
132 filePath := path.Join(dataDir, fileName)
133
134 file, err := os.Open(filePath)
135 if err != nil {
136 log.Fatalf("failed to open file %q: %v", filePath, err)
137 }
138
139 tc := struct {
140 Valid []*validityTestCase `json:"valid"`
141 }{}
142
143 if err := json.NewDecoder(file).Decode(&tc); err != nil {
144 log.Fatalf("failed to decode file %q: %v", filePath, err)
145 }
146
147 seedTestCase(zw, tc.Valid)
148 }
149 }
150
151
152
153 func main() {
154 seedCorpus := os.Args[1]
155 if filepath.Ext(seedCorpus) != ".zip" {
156 log.Fatalf("expected zip file <corpus>.zip, got %s", seedCorpus)
157 }
158
159 zipFile, err := os.Create(seedCorpus)
160 if err != nil {
161 log.Fatalf("failed creating zip file: %v", err)
162 }
163
164 defer func() {
165 err := zipFile.Close()
166 if err != nil {
167 log.Fatalf("failed to close zip file: %v", err)
168 }
169 }()
170
171 zipWriter := zip.NewWriter(zipFile)
172 seedBSONCorpus(zipWriter)
173
174 if err := zipWriter.Close(); err != nil {
175 log.Fatalf("failed to close zip writer: %v", err)
176 }
177 }
178
View as plain text