@@ -1447,3 +1447,102 @@ func TestMatchBits(t *testing.T) {
14471447 }, false )
14481448 })
14491449}
1450+
1451+ func TestMatchMod (t * testing.T ) {
1452+ matchTest (t , bson.M {
1453+ "foo" : int32 (10 ),
1454+ }, func (fn func (bson.M , interface {})) {
1455+ // invalid argument shapes
1456+ fn (bson.M {
1457+ "foo" : bson.M {"$mod" : int32 (1 )},
1458+ }, "$mod: expected array" )
1459+ fn (bson.M {
1460+ "foo" : bson.M {"$mod" : bson.A {int32 (3 )}},
1461+ }, "$mod: expected array of two elements" )
1462+ fn (bson.M {
1463+ "foo" : bson.M {"$mod" : bson.A {int32 (1 ), int32 (2 ), int32 (3 )}},
1464+ }, "$mod: expected array of two elements" )
1465+ fn (bson.M {
1466+ "foo" : bson.M {"$mod" : bson.A {"x" , int32 (0 )}},
1467+ }, "$mod: divisor must be a number" )
1468+ fn (bson.M {
1469+ "foo" : bson.M {"$mod" : bson.A {int32 (2 ), "x" }},
1470+ }, "$mod: remainder must be a number" )
1471+ fn (bson.M {
1472+ "foo" : bson.M {"$mod" : bson.A {int32 (0 ), int32 (0 )}},
1473+ }, "$mod: divisor cannot be zero" )
1474+
1475+ // matching int32 field
1476+ fn (bson.M {
1477+ "foo" : bson.M {"$mod" : bson.A {int32 (3 ), int32 (1 )}},
1478+ }, true )
1479+ fn (bson.M {
1480+ "foo" : bson.M {"$mod" : bson.A {int32 (3 ), int32 (2 )}},
1481+ }, false )
1482+
1483+ // int64 / float64 operands are accepted and truncated
1484+ fn (bson.M {
1485+ "foo" : bson.M {"$mod" : bson.A {int64 (4 ), int64 (2 )}},
1486+ }, true )
1487+ fn (bson.M {
1488+ "foo" : bson.M {"$mod" : bson.A {3.7 , 1.9 }},
1489+ }, true ) // truncated to (3, 1) → 10 % 3 == 1
1490+ fn (bson.M {
1491+ "foo" : bson.M {"$mod" : bson.A {3.0 , 1.0 }},
1492+ }, true )
1493+ })
1494+
1495+ // fractional float field is truncated toward zero
1496+ matchTest (t , bson.M {
1497+ "foo" : 10.7 ,
1498+ }, func (fn func (bson.M , interface {})) {
1499+ fn (bson.M {
1500+ "foo" : bson.M {"$mod" : bson.A {int32 (3 ), int32 (1 )}},
1501+ }, true ) // trunc(10.7)=10, 10%3=1
1502+ fn (bson.M {
1503+ "foo" : bson.M {"$mod" : bson.A {int32 (3 ), int32 (2 )}},
1504+ }, false )
1505+ })
1506+
1507+ // negative dividend retains sign of dividend in remainder
1508+ matchTest (t , bson.M {
1509+ "foo" : int32 (- 7 ),
1510+ }, func (fn func (bson.M , interface {})) {
1511+ fn (bson.M {
1512+ "foo" : bson.M {"$mod" : bson.A {int32 (3 ), int32 (- 1 )}},
1513+ }, true )
1514+ fn (bson.M {
1515+ "foo" : bson.M {"$mod" : bson.A {int32 (3 ), int32 (2 )}},
1516+ }, false )
1517+ })
1518+
1519+ // non-numeric field never matches
1520+ matchTest (t , bson.M {
1521+ "foo" : "bar" ,
1522+ }, func (fn func (bson.M , interface {})) {
1523+ fn (bson.M {
1524+ "foo" : bson.M {"$mod" : bson.A {int32 (1 ), int32 (0 )}},
1525+ }, false )
1526+ })
1527+
1528+ // missing field never matches
1529+ matchTest (t , bson.M {
1530+ "foo" : int32 (1 ),
1531+ }, func (fn func (bson.M , interface {})) {
1532+ fn (bson.M {
1533+ "bar" : bson.M {"$mod" : bson.A {int32 (1 ), int32 (0 )}},
1534+ }, false )
1535+ })
1536+
1537+ // array field unwinds: matches if any element matches
1538+ matchTest (t , bson.M {
1539+ "foo" : bson.A {int32 (3 ), int32 (7 ), int32 (10 )},
1540+ }, func (fn func (bson.M , interface {})) {
1541+ fn (bson.M {
1542+ "foo" : bson.M {"$mod" : bson.A {int32 (5 ), int32 (0 )}},
1543+ }, true ) // 10 % 5 == 0
1544+ fn (bson.M {
1545+ "foo" : bson.M {"$mod" : bson.A {int32 (5 ), int32 (4 )}},
1546+ }, false )
1547+ })
1548+ }
0 commit comments