Skip to content

Commit 01f5af7

Browse files
committed
Rewrite all the bsondump tests in Go and delete the JS tests for this
A few of the JS tests were not ported, per the plan in docs/superpowers
1 parent a8eb9e7 commit 01f5af7

17 files changed

Lines changed: 194 additions & 251 deletions

bsondump/bsondump_test.go

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,17 @@ package bsondump
99
import (
1010
"bytes"
1111
"crypto/rand"
12+
"fmt"
1213
"os"
1314
"os/exec"
1415
"path/filepath"
16+
"regexp"
1517
"strings"
1618
"testing"
1719

1820
"github.com/mongodb/mongo-tools/common/testtype"
1921
"github.com/mongodb/mongo-tools/common/testutil"
22+
"github.com/stretchr/testify/assert"
2023
"github.com/stretchr/testify/require"
2124
"go.mongodb.org/mongo-driver/v2/bson"
2225
)
@@ -260,6 +263,197 @@ func testFromFileWithPositionalArgumentToFile(t *testing.T) {
260263
require.Equal(bufRefStr, bufDumpStr)
261264
}
262265

266+
// TestBsondumpAllTypesDebug verifies that bsondump --type=debug outputs the correct BSON type
267+
// numbers for all non-deprecated BSON types (from all_types.js).
268+
func TestBsondumpAllTypesDebug(t *testing.T) {
269+
testtype.SkipUnlessTestType(t, testtype.UnitTestType)
270+
271+
out, err := runBsondump("--type=debug", "testdata/all_types.bson")
272+
require.NoError(t, err, "bsondump should exit successfully with --type=debug")
273+
274+
assert.Equal(
275+
t,
276+
22,
277+
strings.Count(out, "--- new object ---"),
278+
"should find all 22 documents in all_types.bson",
279+
)
280+
281+
for _, typeNum := range []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 17, 18, -1, 127} {
282+
re := regexp.MustCompile(fmt.Sprintf(`type:\s+%d`, typeNum))
283+
assert.Regexp(t, re, out, "expected type %d in debug output", typeNum)
284+
}
285+
}
286+
287+
// TestBsondumpAllTypesJSON verifies that bsondump --type=json correctly serializes all
288+
// non-deprecated BSON types to Extended JSON (from all_types_json.js).
289+
func TestBsondumpAllTypesJSON(t *testing.T) {
290+
testtype.SkipUnlessTestType(t, testtype.UnitTestType)
291+
292+
oid, err := bson.ObjectIDFromHex("507f1f77bcf86cd799439011")
293+
require.NoError(t, err)
294+
dec, err := bson.ParseDecimal128("1.2E+10")
295+
require.NoError(t, err)
296+
297+
doc := bson.D{
298+
{"double", 2.0},
299+
{"string", "hi"},
300+
{"doc", bson.D{{"x", int32(1)}}},
301+
{"arr", bson.A{int32(1), int32(2)}},
302+
{"binary", bson.Binary{Subtype: 0x00, Data: []byte{0xff, 0xff}}},
303+
{"oid", oid},
304+
{"bool", true},
305+
{"date", bson.DateTime(978312200000)},
306+
{"code", bson.CodeWithScope{Code: "hi", Scope: bson.D{{"x", int32(1)}}}},
307+
{"ts", bson.Timestamp{T: 1, I: 2}},
308+
{"int32", int32(5)},
309+
{"int64", int64(6)},
310+
{"dec", dec},
311+
{"minkey", bson.MinKey{}},
312+
{"maxkey", bson.MaxKey{}},
313+
{"regex", bson.Regex{Pattern: "^abc", Options: "imx"}},
314+
{"symbol", bson.Symbol("i am a symbol")},
315+
{"undefined", bson.Undefined{}},
316+
{"dbpointer", bson.DBPointer{DB: "some.namespace", Pointer: oid}},
317+
{"null", bson.Null{}},
318+
}
319+
320+
bsonData, err := bson.Marshal(doc)
321+
require.NoError(t, err)
322+
tmpFile, err := os.CreateTemp(t.TempDir(), "all_types_*.bson")
323+
require.NoError(t, err)
324+
_, err = tmpFile.Write(bsonData)
325+
require.NoError(t, err)
326+
require.NoError(t, tmpFile.Close())
327+
328+
expectedJSON, err := bson.MarshalExtJSON(doc, true, false)
329+
require.NoError(t, err)
330+
331+
out, err := runBsondump("--type=json", tmpFile.Name())
332+
require.NoError(t, err, "bsondump should exit successfully with 0")
333+
334+
assert.Contains(
335+
t,
336+
out,
337+
"1 objects found",
338+
"should print out all top-level documents from the test data",
339+
)
340+
341+
var jsonLine string
342+
for line := range strings.Lines(out) {
343+
if strings.Contains(line, "$oid") {
344+
jsonLine = line
345+
break
346+
}
347+
}
348+
require.NotEmpty(t, jsonLine, "should find a JSON output line containing Extended JSON")
349+
assert.JSONEq(t, string(expectedJSON), jsonLine)
350+
}
351+
352+
// TestBsondumpDeepNested verifies bsondump handles deeply nested BSON
353+
// documents without error in both JSON and debug modes (from deep_nested.js).
354+
func TestBsondumpDeepNested(t *testing.T) {
355+
testtype.SkipUnlessTestType(t, testtype.UnitTestType)
356+
357+
_, err := runBsondump("--type=json", "testdata/deep_nested.bson")
358+
assert.NoError(t, err, "bsondump should handle deeply nested documents in JSON mode")
359+
360+
_, err = runBsondump("--type=debug", "testdata/deep_nested.bson")
361+
assert.NoError(t, err, "bsondump should handle deeply nested documents in debug mode")
362+
}
363+
364+
// TestBsondumpBadFiles verifies bsondump error handling for malformed BSON
365+
// input with and without --objcheck (from bad_files.js).
366+
func TestBsondumpBadFiles(t *testing.T) {
367+
testtype.SkipUnlessTestType(t, testtype.UnitTestType)
368+
369+
badFiles := []string{
370+
"testdata/bad_cstring.bson",
371+
"testdata/bad_type.bson",
372+
"testdata/invalid_field_name.bson",
373+
"testdata/partial_file.bson",
374+
"testdata/random_bytes.bson",
375+
}
376+
for _, f := range badFiles {
377+
_, err := runBsondump("--objcheck", f)
378+
assert.Error(t, err, "--objcheck %s should exit with error", f)
379+
380+
_, err = runBsondump("--objcheck", "--type=debug", f)
381+
assert.Error(t, err, "--objcheck --type=debug %s should exit with error", f)
382+
}
383+
384+
_, err := runBsondump("--objcheck", "testdata/broken_array.bson")
385+
assert.NoError(t, err, "--objcheck broken_array.bson should succeed")
386+
387+
_, err = runBsondump("--objcheck", "--type=debug", "testdata/broken_array.bson")
388+
assert.NoError(t, err, "--objcheck --type=debug broken_array.bson should succeed")
389+
390+
out, err := runBsondump("testdata/bad_cstring.bson")
391+
assert.NoError(t, err, "bad_cstring.bson without --objcheck should not error")
392+
assert.Contains(
393+
t,
394+
out,
395+
"unable to dump document",
396+
"bad_cstring.bson should report a corrupted document in output",
397+
)
398+
}
399+
400+
// TestBsondumpOptionValidation verifies bsondump accepts valid options and
401+
// rejects invalid ones (from bsondump_options.js).
402+
func TestBsondumpOptionValidation(t *testing.T) {
403+
testtype.SkipUnlessTestType(t, testtype.UnitTestType)
404+
405+
t.Run("invalid --type fails", func(t *testing.T) {
406+
_, err := runBsondump("--type=fake", "testdata/sample.bson")
407+
assert.Error(t, err)
408+
})
409+
t.Run("nonexistent file fails", func(t *testing.T) {
410+
_, err := runBsondump("testdata/does_not_exist.bson")
411+
assert.Error(t, err)
412+
})
413+
t.Run("--noobjcheck fails", func(t *testing.T) {
414+
_, err := runBsondump("--noobjcheck", "testdata/sample.bson")
415+
assert.Error(t, err)
416+
})
417+
t.Run("--collection fails", func(t *testing.T) {
418+
_, err := runBsondump("--collection", "testdata/sample.bson")
419+
assert.Error(t, err)
420+
})
421+
t.Run("multiple positional args fails", func(t *testing.T) {
422+
_, err := runBsondump("testdata/sample.bson", "testdata/sample.bson")
423+
assert.Error(t, err)
424+
})
425+
t.Run("--bsonFile with extra positional arg fails", func(t *testing.T) {
426+
_, err := runBsondump("--bsonFile", "testdata/sample.bson", "testdata/sample.bson")
427+
assert.Error(t, err)
428+
})
429+
t.Run("-vvvv succeeds", func(t *testing.T) {
430+
_, err := runBsondump("-vvvv", "testdata/sample.bson")
431+
assert.NoError(t, err)
432+
})
433+
t.Run("--verbose succeeds", func(t *testing.T) {
434+
_, err := runBsondump("--verbose", "testdata/sample.bson")
435+
assert.NoError(t, err)
436+
})
437+
t.Run("--quiet suppresses status but still outputs data", func(t *testing.T) {
438+
out, err := runBsondump("--quiet", "testdata/sample.bson")
439+
assert.NoError(t, err)
440+
assert.Contains(t, out, "I am a string",
441+
"JSON content should still be output with --quiet")
442+
assert.NotContains(t, out, "objects found",
443+
"status line should be suppressed by --quiet")
444+
})
445+
t.Run("--help succeeds and prints usage", func(t *testing.T) {
446+
out, err := runBsondump("--help")
447+
assert.NoError(t, err)
448+
assert.Contains(t, out, "Usage")
449+
})
450+
t.Run("--version succeeds and prints version", func(t *testing.T) {
451+
out, err := runBsondump("--version")
452+
assert.NoError(t, err)
453+
assert.Contains(t, out, "version")
454+
})
455+
}
456+
263457
func bsondumpCommand(args ...string) *exec.Cmd {
264458
cmd := []string{"go", "run", filepath.Join("..", "bsondump", "main")}
265459
cmd = append(cmd, args...)
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)