Skip to content

Commit

Permalink
move tests for primitives out into puya-ts
Browse files Browse the repository at this point in the history
  • Loading branch information
boblat committed Sep 25, 2024
1 parent de1b8ea commit 332c449
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 10 deletions.
59 changes: 59 additions & 0 deletions tests/primitives/avm-invoker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import * as algokit from '@algorandfoundation/algokit-utils'
import { ABIAppCallArg, ABIReturn } from '@algorandfoundation/algokit-utils/types/app'
import { ApplicationClient } from '@algorandfoundation/algokit-utils/types/app-client'
import { AppSpec } from '@algorandfoundation/algokit-utils/types/app-spec'
import { nullLogger } from '@algorandfoundation/algokit-utils/types/logging'
import { SendTransactionParams } from '@algorandfoundation/algokit-utils/types/transaction'
import { ABIValue } from 'algosdk'
import { randomUUID } from 'crypto'
import { Lazy } from './util'

algokit.Config.configure({ logger: nullLogger })
const ARC4_PREFIX_LENGTH = 2

const algorandClient = Lazy(() => algokit.AlgorandClient.defaultLocalNet())

export const INITIAL_BALANCE_MICRO_ALGOS = Number(20e6)

export const getAlgorandAppClient = async (appSpec: AppSpec) => {
const client = algorandClient()
const defaultSigner = await client.account.kmd.getLocalNetDispenserAccount()
const appClient = algokit.getAppClient({ app: appSpec, resolveBy: 'id', id: 0, sender: defaultSigner.account }, client.client.algod)
await appClient.create({ note: randomUUID() })
return appClient
}

const inovkeMethod = async (
appClient: ApplicationClient,
method: string,
sendParams?: SendTransactionParams,
...methodArgs: ABIAppCallArg[]
): Promise<ABIReturn> => {
const response = await appClient.call({ method, methodArgs, note: randomUUID(), sendParams })
if (!response.return) {
throw new Error(`${method} did not return a value`)
}
if (response.return.decodeError) {
throw response.return.decodeError
}
return response.return
}

export const getAvmResult = async <TResult extends ABIValue>(
{ appClient, sendParams }: { appClient: ApplicationClient; sendParams?: SendTransactionParams },
method: string,
...methodArgs: ABIAppCallArg[]
): Promise<TResult> => {
const result = await inovkeMethod(appClient, method, sendParams, ...methodArgs)
return result.returnValue as TResult
}

export const getAvmResultRaw = async (
{ appClient, sendParams }: { appClient: ApplicationClient; sendParams?: SendTransactionParams },
method: string,
...methodArgs: ABIAppCallArg[]
): Promise<Uint8Array | undefined> => {
const result = await inovkeMethod(appClient, method, sendParams, ...methodArgs)
return result.rawReturnValue?.slice(ARC4_PREFIX_LENGTH)
}

Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { biguint, BigUint, Bytes, internal, Uint64 } from '@algorandfoundation/algo-ts'
import { AppSpec } from '@algorandfoundation/algokit-utils/types/app-spec'
import { describe, expect, it } from 'vitest'
import { MAX_UINT512, MAX_UINT64 } from '../../src/constants'
import appSpecJson from '../artifacts/primitive-ops/data/PrimitiveOpsContract.arc32.json'
import { getAlgorandAppClient, getAvmResult, getAvmResultRaw } from '../avm-invoker'

import appSpecJson from './artifacts/data/PrimitiveOpsContract.arc32.json'
import { getAlgorandAppClient, getAvmResult, getAvmResultRaw } from './avm-invoker'

const MAX_UINT512 = 2n ** 512n - 1n
const MAX_UINT64 = 2n ** 64n - 1n
const asBigUint = (val: bigint | number) => (typeof val === 'bigint' ? BigUint(val) : BigUint(val))

describe('BigUint', async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { bytes, Bytes, internal } from '@algorandfoundation/algo-ts'
import { AppSpec } from '@algorandfoundation/algokit-utils/types/app-spec'
import { describe, expect, it } from 'vitest'
import { MAX_BYTES_SIZE } from '../../src/constants'
import appSpecJson from '../artifacts/primitive-ops/data/PrimitiveOpsContract.arc32.json'
import { getAlgorandAppClient, getAvmResult, getAvmResultRaw } from '../avm-invoker'
import { asUint8Array, getSha256Hash, padUint8Array } from '../util'
import appSpecJson from './artifacts/data/PrimitiveOpsContract.arc32.json'
import { getAlgorandAppClient, getAvmResult, getAvmResultRaw } from './avm-invoker'
import { asUint8Array, getSha256Hash, padUint8Array } from './util'

const MAX_BYTES_SIZE = 4096

describe('Bytes', async () => {
const appClient = await getAlgorandAppClient(appSpecJson as AppSpec)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { internal, uint64, Uint64 } from '@algorandfoundation/algo-ts'
import { AppSpec } from '@algorandfoundation/algokit-utils/types/app-spec'
import { describe, expect, it } from 'vitest'
import { MAX_UINT64 } from '../../src/constants'
import appSpecJson from '../artifacts/primitive-ops/data/PrimitiveOpsContract.arc32.json'
import { getAlgorandAppClient, getAvmResult } from '../avm-invoker'
import appSpecJson from './artifacts/data/PrimitiveOpsContract.arc32.json'
import { getAlgorandAppClient, getAvmResult } from './avm-invoker'

const MAX_UINT64 = 2n ** 64n - 1n
const asUint64 = (val: bigint | number) => (typeof val === 'bigint' ? Uint64(val) : Uint64(val))

describe('Unit64', async () => {
Expand Down
26 changes: 26 additions & 0 deletions tests/primitives/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { internal } from '@algorandfoundation/algo-ts'
import { createHash } from 'crypto'

export const padUint8Array = (arr: Uint8Array, padSize: number): Uint8Array => {
const paddedUint8Array = new Uint8Array(arr.length + padSize).fill(0)
arr.forEach((v, i) => (paddedUint8Array[padSize + i] = v))
return paddedUint8Array
}

export const asUint8Array = (value: internal.primitives.StubBytesCompat): Uint8Array =>
internal.primitives.BytesCls.fromCompat(value).asUint8Array()

export const getSha256Hash = (value: Uint8Array): Uint8Array => new Uint8Array(createHash('sha256').update(value).digest())

const NoValue = Symbol('no-value')
type LazyInstance<T> = () => T
export const Lazy = <T>(factory: () => T): LazyInstance<T> => {
let val: T | typeof NoValue = NoValue

return () => {
if (val === NoValue) {
val = factory()
}
return val
}
}

0 comments on commit 332c449

Please sign in to comment.