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

Improve Test Coverage for packages/web3-wallet/src #464

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
93 changes: 87 additions & 6 deletions packages/web3-wallet/src/password-crypto.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,93 @@ You should have received a copy of the GNU Lesser General Public License
along with the library. If not, see <http://www.gnu.org/licenses/>.
*/

import { decrypt } from './password-crypto'
import { encrypt, decrypt } from './password-crypto' // Replace with the correct file path

describe('password-crypto', () => {
it('should raise an error if payload version is not 1', () => {
const password = 'passw0rd'
const payloadRaw = '{"version":2}'
expect(() => decrypt(password, payloadRaw)).toThrow('Invalid version: got 2, expected: 1')
describe('Encryption and Decryption', () => {
const password = 'secure-password'
const testMessage = 'This is a test message'

describe('encrypt', () => {
it('should return a valid JSON string containing salt, iv, encrypted data, and version', () => {
const encryptedPayload = encrypt(password, testMessage)
const parsedPayload = JSON.parse(encryptedPayload)

expect(parsedPayload).toHaveProperty('salt')
expect(parsedPayload).toHaveProperty('iv')
expect(parsedPayload).toHaveProperty('encrypted')
expect(parsedPayload).toHaveProperty('version', 1)

expect(typeof parsedPayload.salt).toBe('string')
expect(typeof parsedPayload.iv).toBe('string')
expect(typeof parsedPayload.encrypted).toBe('string')
})

it('should produce unique salt and IV for each encryption', () => {
const payload1 = JSON.parse(encrypt(password, testMessage))
const payload2 = JSON.parse(encrypt(password, testMessage))

expect(payload1.salt).not.toBe(payload2.salt)
expect(payload1.iv).not.toBe(payload2.iv)
expect(payload1.encrypted).not.toBe(payload2.encrypted)
})
})

describe('decrypt', () => {
it('should correctly decrypt an encrypted message using the same password', () => {
const encryptedPayload = encrypt(password, testMessage)
const decryptedMessage = decrypt(password, encryptedPayload)

expect(decryptedMessage).toBe(testMessage)
})

it('should throw an error when the password is incorrect', () => {
const encryptedPayload = encrypt(password, testMessage)
const wrongPassword = 'wrong-password'

expect(() => decrypt(wrongPassword, encryptedPayload)).toThrow(/Unsupported state or unable to authenticate data/)
})

it('should throw an error if the version is not 1', () => {
const encryptedPayload = encrypt(password, testMessage)
const parsedPayload = JSON.parse(encryptedPayload)
parsedPayload.version = 2

expect(() => decrypt(password, JSON.stringify(parsedPayload))).toThrow(/Invalid version: got 2, expected: 1/)
})

it('should throw an error if the salt or IV is missing', () => {
const encryptedPayload = encrypt(password, testMessage)
const parsedPayload = JSON.parse(encryptedPayload)

delete parsedPayload.salt

expect(() => decrypt(password, JSON.stringify(parsedPayload))).toThrow()
})
})

describe('edge cases', () => {
it('should handle an empty message for encryption and decryption', () => {
const emptyMessage = ''
const encryptedPayload = encrypt(password, emptyMessage)
const decryptedMessage = decrypt(password, encryptedPayload)

expect(decryptedMessage).toBe(emptyMessage)
})

it('should handle large messages for encryption and decryption', () => {
const largeMessage = 'A'.repeat(1_000_000) // 1 MB of data
Copy link

@pragmaxim pragmaxim Dec 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be happy with 500_000 since this single test takes 700ms (on CI it could be twice as much) and it would add up a lot in the big picture, I guess that supporting 0.5MB messages is enough

const encryptedPayload = encrypt(password, largeMessage)
const decryptedMessage = decrypt(password, encryptedPayload)

expect(decryptedMessage).toBe(largeMessage)
})

it('should handle messages with special characters and emojis', () => {
const specialMessage = 'Special characters: 🚀✨🎉!@#$%^&*()_+'
const encryptedPayload = encrypt(password, specialMessage)
const decryptedMessage = decrypt(password, encryptedPayload)

expect(decryptedMessage).toBe(specialMessage)
})
})
})
69 changes: 67 additions & 2 deletions packages/web3-wallet/src/privatekey-wallet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,77 @@ along with the library. If not, see <http://www.gnu.org/licenses/>.
import { web3 } from '@alephium/web3'
import { PrivateKeyWallet } from './privatekey-wallet'

describe('privatekey wallet', () => {
it('test the length of private key', () => {
describe('PrivateKeyWallet', () => {
beforeAll(() => {
// Set the node provider before running the tests
web3.setCurrentNodeProvider('http://127.0.0.1:22973')
})

it('should generate a private key of correct length', () => {
for (let i = 0; i < 100; i++) {
const wallet = PrivateKeyWallet.Random()
expect(wallet.privateKey.length).toEqual(64)
}
})

it('should generate unique private keys', () => {
const wallets = new Set<string>()
for (let i = 0; i < 100; i++) {
const wallet = PrivateKeyWallet.Random()
wallets.add(wallet.privateKey)
}
expect(wallets.size).toEqual(100)
})

it('should generate a wallet with valid address and public key', () => {
const wallet = PrivateKeyWallet.Random()
expect(wallet.address).toBeDefined()
expect(wallet.publicKey).toBeDefined()
expect(wallet.address.length).toBeGreaterThan(0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets verify the exact length of address and publicKey here.

expect(wallet.publicKey.length).toBeGreaterThan(0)
})

it('should correctly sign raw data', async () => {
const wallet = PrivateKeyWallet.Random()
const hexString = 'deadbeef'
const signature = await wallet.signRaw(wallet.address, hexString)

expect(signature).toBeDefined()
expect(typeof signature).toBe('string')
// Optionally add more checks to validate the signature
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please verify if the signature is valid, we can use the verifySignature function.

})

it('should throw an error if signing with an incorrect address', async () => {
const wallet = PrivateKeyWallet.Random()
const hexString = 'deadbeef'

await expect(wallet.signRaw('invalid-address', hexString)).rejects.toThrow('Unmatched signer address')
})

it('should create a wallet from a mnemonic', () => {
const mnemonic = 'test test test test test test test test test test test junk'
const wallet = PrivateKeyWallet.FromMnemonic({ mnemonic })

expect(wallet.privateKey).toBeDefined()
expect(wallet.publicKey).toBeDefined()
expect(wallet.address).toBeDefined()
})

it('should create a wallet with a specific group from a mnemonic', () => {
const mnemonic = 'test test test test test test test test test test test junk'
const targetGroup = 1
const wallet = PrivateKeyWallet.FromMnemonicWithGroup(mnemonic, targetGroup)

expect(wallet.group).toEqual(targetGroup)
expect(wallet.privateKey).toBeDefined()
expect(wallet.publicKey).toBeDefined()
expect(wallet.address).toBeDefined()
})

it('should generate a wallet with the correct target group', () => {
const targetGroup = 3
const wallet = PrivateKeyWallet.Random(targetGroup)

expect(wallet.group).toEqual(targetGroup)
})
})