Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests #98

Merged
merged 3 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions Blockchain/Tests/BlockchainTests/InMemoryDataProviderTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import Testing
import Utils

@testable import Blockchain

struct InMemoryDataProviderTests {
@Test func testInitialization() async throws {
let genesis = StateRef(State.dummy(config: ProtocolConfigRef.mainnet))
let provider = await InMemoryDataProvider(genesis: genesis)

#expect(await (provider.getHeads()) == [Data32()])
#expect(await (provider.getFinalizedHead()) == Data32())
}

@Test func testAddAndRetrieveBlock() async throws {
let genesis = StateRef(State.dummy(config: ProtocolConfigRef.mainnet))
let provider = await InMemoryDataProvider(genesis: genesis)

let block = BlockRef(Block.dummy(config: ProtocolConfigRef.mainnet))
await provider.add(block: block)

#expect(await (provider.hasBlock(hash: block.hash)) == true)
#expect(try await (provider.getBlock(hash: block.hash)) == block)
await #expect(throws: BlockchainDataProviderError.noData) {
try await provider.getBlock(hash: Data32())
}
}

@Test func testAddAndRetrieveState() async throws {
let genesis = StateRef(State.dummy(config: ProtocolConfigRef.mainnet))
let provider = await InMemoryDataProvider(genesis: genesis)

let state = StateRef(State.dummy(config: ProtocolConfigRef.mainnet))
await provider.add(state: state)

#expect(await (provider.hasState(hash: state.value.lastBlockHash)) == true)
#expect(try await (provider.getState(hash: state.value.lastBlockHash)) == state)
}

@Test func testUpdateHead() async throws {
let genesis = StateRef(State.dummy(config: ProtocolConfigRef.mainnet))
let provider = await InMemoryDataProvider(genesis: genesis)

let newBlock = BlockRef(Block.dummy(config: ProtocolConfigRef.mainnet))

await provider.add(block: newBlock)
try await provider.updateHead(hash: newBlock.hash, parent: Data32())

#expect(await provider.isHead(hash: newBlock.hash) == true)
#expect(await provider.isHead(hash: Data32()) == false)
await #expect(throws: BlockchainDataProviderError.noData) {
try await provider.updateHead(hash: newBlock.hash, parent: Data32())
}
}

@Test func testSetFinalizedHead() async throws {
let genesis = StateRef(State.dummy(config: ProtocolConfigRef.mainnet))
let provider = await InMemoryDataProvider(genesis: genesis)

let block = BlockRef(Block.dummy(config: ProtocolConfigRef.mainnet))
await provider.add(block: block)
await provider.setFinalizedHead(hash: block.hash)

#expect(await (provider.getFinalizedHead()) == block.hash)
}

@Test func testRemoveHash() async throws {
let genesis = StateRef(State.dummy(config: ProtocolConfigRef.mainnet))
let provider = await InMemoryDataProvider(genesis: genesis)

let state = StateRef(State.dummy(config: ProtocolConfigRef.dev))
let timeslotIndex = state.value.timeslot
await provider.add(state: state)

#expect(await (provider.hasState(hash: state.value.lastBlockHash)) == true)
#expect(await (provider.getBlockHash(byTimeslot: timeslotIndex).contains(state.value.lastBlockHash)) == true)

await provider.remove(hash: state.value.lastBlockHash)

#expect(await (provider.hasState(hash: state.value.lastBlockHash)) == false)
#expect(await (provider.getBlockHash(byTimeslot: timeslotIndex).contains(state.value.lastBlockHash)) == false)
}
}
1 change: 0 additions & 1 deletion Utils/Sources/Utils/ConfigLimitedSizeArray.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import Codec

// TODO: add tests
// TODO: consider using a circular buffer instead of a regular array to reduce memory usage

public enum ConfigLimitedSizeArrayError: Swift.Error {
Expand Down
1 change: 0 additions & 1 deletion Utils/Sources/Utils/LimitedSizeArray.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import Codec

// TODO: add tests
public struct LimitedSizeArray<T, TMinLength: ConstInt, TMaxLength: ConstInt> {
public private(set) var array: [T]
public static var minLength: Int {
Expand Down
145 changes: 145 additions & 0 deletions Utils/Tests/UtilsTests/ConfigLimitedSizeArrayTest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import Codec
import Foundation
import Testing

@testable import Utils

struct MinLength3: ReadInt {
typealias TConfig = Int

static func read(config _: Int) -> Int {
3
}
}

struct MaxLength5: ReadInt {
typealias TConfig = Int

static func read(config _: Int) -> Int {
5
}
}

struct ConfigLimitedSizeArrayTests {
@Test func initWithDefaultValue() throws {
let config = 0
let defaultValue = 1
let array = try ConfigLimitedSizeArray<Int, MinLength3, MaxLength5>(config: config, defaultValue: defaultValue)
#expect(array.array == [1, 1, 1])
#expect(array.count == 3)
}

@Test func initWithArrayWithinBounds() throws {
let config = 0
let array = try ConfigLimitedSizeArray<Int, MinLength3, MaxLength5>(config: config, array: [1, 2, 3])
#expect(array.array == [1, 2, 3])
#expect(array.count == 3)
}

@Test func initWithArrayOutOfBounds() throws {
let config = 0
// Array smaller than min length
#expect(throws: ConfigLimitedSizeArrayError.tooFewElements) {
_ = try ConfigLimitedSizeArray<Int, MinLength3, MaxLength5>(config: config, array: [1, 2])
}

// Array larger than max length
#expect(throws: ConfigLimitedSizeArrayError.tooManyElements) {
_ = try ConfigLimitedSizeArray<Int, MinLength3, MaxLength5>(config: config, array: [1, 2, 3, 4, 5, 6])
}
}

@Test func appendElement() throws {
let config = 0
var array = try ConfigLimitedSizeArray<Int, MinLength3, MaxLength5>(config: config, array: [1, 2, 3])
try array.append(4)
#expect(array.array == [1, 2, 3, 4])
#expect(array.count == 4)

// Appending beyond max length
#expect(throws: ConfigLimitedSizeArrayError.tooManyElements) {
try array.append(5)
try array.append(6)
}
}

@Test func safeAppendElement() throws {
let config = 0
var array = try ConfigLimitedSizeArray<Int, MinLength3, MaxLength5>(config: config, array: [1, 2, 3])
array.safeAppend(4)
#expect(array.array == [1, 2, 3, 4])
#expect(array.count == 4)

// Safe append when max length is reached
array.safeAppend(5)
array.safeAppend(6)
#expect(array.array == [2, 3, 4, 5, 6])
#expect(array.count == 5)
}

@Test func insertElement() throws {
let config = 0
var array = try ConfigLimitedSizeArray<Int, MinLength3, MaxLength5>(config: config, array: [1, 2, 3])
try array.insert(0, at: 1)
#expect(array.array == [1, 0, 2, 3])
#expect(array.count == 4)

// Inserting beyond max length
#expect(throws: ConfigLimitedSizeArrayError.tooManyElements) {
try array.insert(5, at: 0)
try array.insert(6, at: 0)
}

// Inserting at invalid index
#expect(throws: ConfigLimitedSizeArrayError.invalidIndex) {
try array.insert(7, at: -1)
}

#expect(throws: ConfigLimitedSizeArrayError.invalidIndex) {
try array.insert(8, at: 10)
}
}

@Test func removeElement() throws {
let config = 0
var array = try ConfigLimitedSizeArray<Int, MinLength3, MaxLength5>(config: config, array: [1, 2, 3, 4])
let removed = try array.remove(at: 2)
#expect(removed == 3)
#expect(array.array == [1, 2, 4])
#expect(array.count == 3)

// Removing below min length
#expect(throws: ConfigLimitedSizeArrayError.tooFewElements) {
_ = try array.remove(at: 0)
_ = try array.remove(at: 0)
}

// Removing at invalid index
#expect(throws: ConfigLimitedSizeArrayError.invalidIndex) {
_ = try array.remove(at: -1)
}

#expect(throws: ConfigLimitedSizeArrayError.invalidIndex) {
_ = try array.remove(at: 10)
}
}

@Test func equatable() throws {
let config = 0
let array1 = try ConfigLimitedSizeArray<Int, MinLength3, MaxLength5>(config: config, array: [1, 2, 3])
let array2 = try ConfigLimitedSizeArray<Int, MinLength3, MaxLength5>(config: config, array: [1, 2, 3])
let array3 = try ConfigLimitedSizeArray<Int, MinLength3, MaxLength5>(config: config, array: [3, 2, 1])

#expect(array1 == array2)
#expect(array1 != array3)
}

// TODO: Codable
// @Test func codable() throws {
// let config = 0
// let array = try ConfigLimitedSizeArray<Int, MinLength3, MaxLength5>(config: config, array: [1, 2, 3])
// let encoded = try JamEncoder.encode(array)
// let decoded = try JamDecoder.decode(ConfigLimitedSizeArray<Int, MinLength3, MaxLength5>.self, from: encoded, withConfig: config)
// #expect(decoded == array)
// }
}
71 changes: 71 additions & 0 deletions Utils/Tests/UtilsTests/LimitedSizeArrayTest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import Codec
import Foundation
import Testing

@testable import Utils

struct ConstInt5: ConstInt {
static let value = 5
}

struct ConstInt10: ConstInt {
static let value = 10
}

struct ConstInt0: ConstInt {
static let value = 0
}

struct LimitedSizeArrayTests {
@Test func initWithDefaultValue() throws {
let defaultValue = 1
let array = LimitedSizeArray<Int, ConstInt5, ConstInt10>(defaultValue: defaultValue)
#expect(array.array == [1, 1, 1, 1, 1])
#expect(array.count == 5)
}

@Test func expressibleByArrayLiteral() throws {
let array: LimitedSizeArray<Int, ConstInt5, ConstInt10> = [1, 2, 3, 4, 5]
#expect(array.array == [1, 2, 3, 4, 5])
}

@Test func appendElement() throws {
var array = LimitedSizeArray<Int, ConstInt5, ConstInt10>([1, 2, 3, 4, 5])
array.append(6)
#expect(array.array == [1, 2, 3, 4, 5, 6])
#expect(array.count == 6)
}

@Test func insertElement() throws {
var array = LimitedSizeArray<Int, ConstInt5, ConstInt10>([1, 2, 3, 4, 5])
array.insert(0, at: 2)
#expect(array.array == [1, 2, 0, 3, 4, 5])
#expect(array.count == 6)
}

@Test func removeElement() throws {
var array = LimitedSizeArray<Int, ConstInt5, ConstInt10>([1, 2, 3, 4, 5, 6])
let removed = array.remove(at: 2)
#expect(removed == 3)
#expect(array.array == [1, 2, 4, 5, 6])
#expect(array.count == 5)
}

@Test func equatable() throws {
let array1: LimitedSizeArray<Int, ConstInt5, ConstInt10> = [1, 2, 3, 4, 5]
let array2: LimitedSizeArray<Int, ConstInt5, ConstInt10> = [1, 2, 3, 4, 5]
let array3: LimitedSizeArray<Int, ConstInt5, ConstInt10> = [5, 4, 3, 2, 1]

#expect(array1 == array2)
#expect(array1 != array3)
}

// TODO: Codable
// @Test func codable() throws {
// let array: LimitedSizeArray<Int, ConstInt5, ConstInt10> = [1, 2, 3, 4, 5]
// let encoded = try JamEncoder.encode(array)
// let decoded = try JamDecoder.decode(LimitedSizeArray<Int, ConstInt5, ConstInt10>.self, from: encoded, withConfig: ())

// #expect(decoded == array)
// }
}
Loading