Skip to content

Commit

Permalink
Add test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
darkdrag00nv2 committed Nov 26, 2023
1 parent 71d2a1d commit b6bec33
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 5 deletions.
92 changes: 90 additions & 2 deletions runtime/runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"encoding/hex"
"errors"
"fmt"
"math"
"strconv"
"strings"
"sync"
Expand Down Expand Up @@ -4745,7 +4746,7 @@ func TestRuntimeBlock(t *testing.T) {
)
}

func TestRuntimeRandom(t *testing.T) {
func TestRuntimeRandomWithUnsafeRandom(t *testing.T) {

t.Parallel()

Expand All @@ -4754,7 +4755,7 @@ func TestRuntimeRandom(t *testing.T) {
script := []byte(`
transaction {
prepare() {
let rand1 = revertibleRandom()
let rand1 = revertibleRandom<UInt64>()
log(rand1)
let rand2 = unsafeRandom()
log(rand2)
Expand Down Expand Up @@ -4796,6 +4797,93 @@ func TestRuntimeRandom(t *testing.T) {
)
}

func getFixedSizeUnsignedIntegerForSemaType(ty sema.Type) cadence.Value {
switch ty {
case sema.UInt8Type:
return cadence.NewUInt8(math.MaxUint8)
case sema.UInt16Type:
return cadence.NewUInt16(math.MaxUint16)
case sema.UInt32Type:
return cadence.NewUInt32(math.MaxUint32)
case sema.UInt64Type:
return cadence.NewUInt64(math.MaxUint64)
case sema.UInt128Type:
value, _ := cadence.NewUInt128FromBig(sema.UInt128TypeMaxIntBig)
return value
case sema.UInt256Type:
value, _ := cadence.NewUInt256FromBig(sema.UInt256TypeMaxIntBig)
return value

case sema.Word8Type:
return cadence.NewWord8(math.MaxUint8)
case sema.Word16Type:
return cadence.NewWord16(math.MaxUint16)
case sema.Word32Type:
return cadence.NewWord32(math.MaxUint32)
case sema.Word64Type:
return cadence.NewWord64(math.MaxUint64)
case sema.Word128Type:
value, _ := cadence.NewWord128FromBig(sema.Word128TypeMaxIntBig)
return value
case sema.Word256Type:
value, _ := cadence.NewWord256FromBig(sema.Word256TypeMaxIntBig)
return value
}

panic(fmt.Sprintf("Broken test. Trying to get fixed size unsigned integer for ty: %s", ty))
}

func TestRuntimeRandom(t *testing.T) {

t.Parallel()

script := `
pub fun main(): %[1]s {
let rand = revertibleRandom<%[1]s>()
return rand
}
`

runValidCaseWithoutModulo := func(t *testing.T, ty sema.Type) {
t.Run(ty.String(), func(t *testing.T) {
t.Parallel()

nextScriptLocation := newScriptLocationGenerator()

runtime := newTestInterpreterRuntime()
value, err := runtime.ExecuteScript(
Script{
Source: []byte(fmt.Sprintf(script, ty.String())),
},
Context{
Interface: &testRuntimeInterface{
readRandom: func(buffer []byte) error {
for i := 0; i < len(buffer); i++ {
buffer[i] = 0xff
}
return nil
},
},
Location: nextScriptLocation(),
},
)
require.NoError(t, err)

require.Equal(t, getFixedSizeUnsignedIntegerForSemaType(ty), value)
})
}

for _, ty := range sema.AllFixedSizeUnsignedIntegerTypes {
switch ty {
case sema.FixedSizeUnsignedIntegerType:
continue

default:
runValidCaseWithoutModulo(t, ty)
}
}
}

func TestRuntimeTransactionTopLevelDeclarations(t *testing.T) {

t.Parallel()
Expand Down
4 changes: 1 addition & 3 deletions runtime/stdlib/random.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,9 @@ var revertibleRandomFunctionType = func() *sema.FunctionType {
type RandomGenerator interface {
// ReadRandom reads pseudo-random bytes into the input slice, using distributed randomness.
// The number of bytes read is equal to the length of input slice.
// TODO: Pass the modulo parameter?
ReadRandom([]byte) error
}

// TODO: Take modulo and pass to ReadRandom.
func getRandomBytes(generator RandomGenerator, numBytes int) []byte {
buffer := make([]byte, numBytes)

Expand Down Expand Up @@ -186,7 +184,7 @@ func NewRevertibleRandomFunction(generator RandomGenerator) StandardLibraryValue
return interpreter.NewWord256ValueFromBigInt(
inter,
func() *big.Int {
buffer := getRandomBytes(generator, 16)
buffer := getRandomBytes(generator, 32)
return interpreter.LittleEndianBytesToUnsignedBigInt(buffer)
},
)
Expand Down
84 changes: 84 additions & 0 deletions runtime/tests/checker/builtinfunctions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (

"github.com/onflow/cadence/runtime/common"
"github.com/onflow/cadence/runtime/sema"
"github.com/onflow/cadence/runtime/stdlib"
)

func TestCheckToString(t *testing.T) {
Expand Down Expand Up @@ -268,3 +269,86 @@ func TestCheckFromBigEndianBytes(t *testing.T) {
}
}
}

type testRandomGenerator struct{}

func (*testRandomGenerator) ReadRandom([]byte) error {
return nil
}

func TestCheckRevertibleRandom(t *testing.T) {

t.Parallel()

baseValueActivation := sema.NewVariableActivation(sema.BaseValueActivation)
baseValueActivation.DeclareValue(stdlib.NewRevertibleRandomFunction(&testRandomGenerator{}))
options := ParseAndCheckOptions{
Config: &sema.Config{
BaseValueActivationHandler: func(_ common.Location) *sema.VariableActivation {
return baseValueActivation
},
},
}

runCase := func(t *testing.T, ty sema.Type, code string) {
checker, err := ParseAndCheckWithOptions(t, code, options)

require.NoError(t, err)

resType := RequireGlobalValue(t, checker.Elaboration, "rand")
require.Equal(t, ty, resType)
}

runValidCaseWithoutModulo := func(t *testing.T, ty sema.Type) {
t.Run(fmt.Sprintf("revertibleRandom<%s>_no_modulo", ty), func(t *testing.T) {
t.Parallel()

code := fmt.Sprintf("let rand = revertibleRandom<%s>()", ty)
runCase(t, ty, code)
})
}

runValidCaseWithModulo := func(t *testing.T, ty sema.Type) {
t.Run(fmt.Sprintf("revertibleRandom<%s>_modulo", ty), func(t *testing.T) {
t.Parallel()

code := fmt.Sprintf("let rand = revertibleRandom<%[1]s>(modulo: %[1]s(1))", ty)
runCase(t, ty, code)
})
}

runInvalidCase := func(t *testing.T, testName string, code string, expectedErrors []error) {
t.Run(testName, func(t *testing.T) {
t.Parallel()

_, err := ParseAndCheckWithOptions(t, code, options)

errs := RequireCheckerErrors(t, err, len(expectedErrors))
for i := range expectedErrors {
assert.IsType(t, expectedErrors[i], errs[i])
}
})
}

for _, ty := range sema.AllFixedSizeUnsignedIntegerTypes {
switch ty {
case sema.FixedSizeUnsignedIntegerType:
continue

default:
runValidCaseWithoutModulo(t, ty)
runValidCaseWithModulo(t, ty)
}
}

runInvalidCase(t, "revertibleRandom<Int>", "let rand = revertibleRandom<Int>()", []error{&sema.TypeMismatchError{}})
runInvalidCase(t, "revertibleRandom<String>", "let rand = revertibleRandom<String>(modulo: \"abcd\")", []error{&sema.TypeMismatchError{}})
runInvalidCase(t, "missing_argument_label", "let rand = revertibleRandom<UInt256>(UInt256(1))", []error{&sema.MissingArgumentLabelError{}})
runInvalidCase(t, "incorrect_argument_label", "let rand = revertibleRandom<UInt256>(typo: UInt256(1))", []error{&sema.IncorrectArgumentLabelError{}})
runInvalidCase(t, "too_many_args", "let rand = revertibleRandom<UInt256>(modulo: UInt256(1), 2, 3)", []error{&sema.ExcessiveArgumentsError{}})
runInvalidCase(t, "modulo type mismatch", "let rand = revertibleRandom<UInt256>(modulo: UInt128(1))", []error{&sema.TypeParameterTypeMismatchError{}, &sema.TypeMismatchError{}})
runInvalidCase(t, "string modulo", "let rand = revertibleRandom<UInt256>(modulo: \"abcd\")", []error{&sema.TypeParameterTypeMismatchError{}, &sema.TypeMismatchError{}})

// This is an error since we do not support type inference of function arguments.
runInvalidCase(t, "missing_typeinference", "let rand = revertibleRandom<UInt256>(modulo: 1)", []error{&sema.TypeParameterTypeMismatchError{}})
}

0 comments on commit b6bec33

Please sign in to comment.