bcsc-core-native-testing
- Repo stars 0
- Author updated Live
- Author repo skills-registry
- Domain
- Writing
- Compatible agents
-
- Claude Code
- Cursor
- Cline
- Codex
- Windsurf
- Gemini CLI
- +20
- Trust score
- 88 / 100 · community maintained
- Author / version / license
- @tomevault-io · no license declared
- Token usage
- Lean
- Setup complexity
- Plug-and-play
- External API key
- Not required
- Operating systems
- Unspecified (assume cross-platform)
- Runtime requirements
- No special requirements
- Permissions
-
- Read-only
- Write / modify
- Network behavior
- Local-only
- Install commands
- 26 variants
Profile is derived at build time from SKILL.md and install vectors. Subject to drift from author intent.
Heads up: 未限定 allowed-tools,默认拥有全部工具权限。
---
name: bcsc-core-native-testing
description: Create native unit tests for Swift (iOS) and Kotlin (Android) code in the bcsc-core package. USE…
category: writing
runtime: no special runtime
---
# bcsc-core-native-testing output preview
## PART A: Task fit
- Use case: Create native unit tests for Swift (iOS) and Kotlin (Android) code in the bcsc-core package. USE WHEN: testing native code, adding unit tests for native modules, writing XCTest or JUnit tests for bcsc-core, mocking native protocols or interfaces. DO NOT USE FOR: TypeScript/React tests, UI integration tests, or E2E tests. Use when this capability is needed..
- Inputs: target material, constraints, expected output, and acceptance criteria.
- Evidence boundary: follow “Overview / Test Infrastructure / iOS — XCTest via SPM” and do not present inference as author intent.
## PART B: Execution result
- **01** The card summarizes the use case; runtime output centers on “Create native unit tests for Swift (iOS) and Kotlin (Android) code in the bcsc-core package. USE WHEN: testing native code, adding unit tests for native modules, writing XCTest or JUnit tests for bcsc-core, mocking native protocols or interfaces. DO NOT USE FOR: TypeScript/React tests, UI integration tests, or E2E tests. Use when this capability is needed.”.
- **02** When the source has headings, the agent prioritizes “Overview / Test Infrastructure / iOS — XCTest via SPM” so the result follows the author’s structure.
- **03** Typical output includes task judgment, concrete steps, required commands or file edits, validation, and follow-up options.
- **04** Risk context follows the fingerprint: read files, write/modify files; mostly runs locally; usually needs no extra API key.
## Running Rules
- read files, write/modify files; mostly runs locally; usually needs no extra API key.
- Validate with a small sample before expanding scope.
- Return the result, validation criteria, and next iteration options. The source does not require a stable slash command. After installation, invoke the skill by name and describe the task.
Name target files or source material, expected output, forbidden changes, and whether network or shell access is allowed. Permission fingerprint: read files, write/modify files.
Start with a small task and check whether the result follows “Overview / Test Infrastructure / iOS — XCTest via SPM”. Inspect diffs, logs, previews, or tests before expanding scope.
Confirm the final output includes a concrete result, evidence, and next action. If it stays generic, tighten inputs, boundaries, and acceptance criteria.
---
name: bcsc-core-native-testing
description: Create native unit tests for Swift (iOS) and Kotlin (Android) code in the bcsc-core package. USE…
category: writing
source: tomevault-io/skills-registry
---
# bcsc-core-native-testing
## When to use
- Create native unit tests for Swift (iOS) and Kotlin (Android) code in the bcsc-core package. USE WHEN: testing native…
- Use it when the task has clear inputs, repeatable steps, and validation criteria.
## What to provide
- Target material, scope, expected result, and forbidden changes.
- Whether network, commands, file writes, or external services are allowed.
## Execution rules
- Organize steps around “Overview / Test Infrastructure / iOS — XCTest via SPM” and keep inference separate from source facts.
- read files, write/modify files; mostly runs locally; usually needs no extra API key.
- Validate with a small sample before expanding the task.
## Output requirements
- Return the deliverable, key evidence, validation method, and next action.
- Mark missing information as unknown; do not invent commands, platforms, or dependencies. The author source anchors workflow facts; repository files anchor sources and commands; Fluxly only adds fit, limitations, and quality judgment.
skill "bcsc-core-native-testing" {
input -> user goal + target files + boundaries + acceptance criteria
context -> Overview / Test Infrastructure / iOS — XCTest via SPM
rules -> SKILL.md triggers / order / output contract
runtime -> no special runtime | read files, write/modify files | mostly runs locally
guardrails -> usually needs no extra API key + small-sample validation + diff/log review
output -> copyable result + checklist + next iteration
} bcsc-core Native Unit Testing
Overview
This skill guides creation of native unit tests for the packages/bcsc-core module, which contains Swift (iOS) and Kotlin (Android) implementations of authentication, PIN management, keychain storage, token services, and device authentication.
The codebase already uses protocol-based dependency injection on iOS and interface/class-based injection on Android, making it straightforward to create mock implementations for isolated unit testing.
Test Infrastructure
iOS — XCTest via SPM
Tests are built with Swift Package Manager using the package manifest at packages/bcsc-core/Package.swift. The key concepts:
BcscCoreTestabletarget: A subset of production iOS source files compiled for the simulator (without React Native / CocoaPods dependencies). Only files listed in thesources:array are included.BcscCoreTeststest target: XCTest files underios/BcscCoreTests/, compiled with@testable import BcscCoreTestable.SPM_BUILDflag: A Swift compiler define set inPackage.swiftviaswiftSettings: [.define("SPM_BUILD")]. The fileios/SPMCompat.swiftuses#if SPM_BUILDto provide lightweight stubs (e.g.,SecureRandom,Data.arrayOfBytes()) for types from JWE files that aren't included in the SPM target.- Scheme name: xcodebuild uses
BcscCoreTests-Package(SPM auto-appends-Package).
Adding a new iOS source file to the test target
If the code under test references types in a file not yet in Package.swift, add it to the sources: array in the BcscCoreTestable target. If that file depends on types from excluded files (e.g., JWE/crypto), add stubs to SPMCompat.swift behind #if SPM_BUILD.
Adding a new iOS test file
- Create a new
.swiftfile inios/BcscCoreTests/. - Import frameworks and the testable module:
import LocalAuthentication // if testing LAPolicy/biometric types import XCTest @testable import BcscCoreTestable - Write
XCTestCasesubclasses. Follow the naming convention{ClassUnderTest}Tests. - Run with
yarn test:iosor directly:xcodebuild test -scheme BcscCoreTests-Package \ -destination 'platform=iOS Simulator,name=iPhone 16,OS=latest' \ -skipPackagePluginValidation
Android — JUnit 4 + MockK
Tests live under android/src/test/java/com/bcsccore/ mirroring the main source package structure.
Dependencies (in android/build.gradle)
testImplementation 'junit:junit:4.13.2'
testImplementation 'io.mockk:mockk:1.13.8'
testImplementation 'org.robolectric:robolectric:4.11.1'
testImplementation 'androidx.test:core:1.5.0'
Adding a new Android test file
- Create a Kotlin file in
android/src/test/java/com/bcsccore/{subpackage}/, matching the source package. - Write standard JUnit 4 test classes with
@Testmethods. - Use
io.mockk.mockk<T>()andevery { ... } returns ...for mocking. - Run with
yarn test:androidor directly:cd android && ./gradlew test
Running all tests
yarn test # runs test:ios then test:android
yarn test:ios # iOS only
yarn test:android # Android only
Mocking Strategy
iOS — Protocol Conformance
The codebase defines protocols for all service boundaries. Create mock classes that conform to the protocol and expose controllable properties:
final class MockPINService: PINServiceProtocol {
var verifyResult: String? // control return value
var setPINResult: String = "mock-hash"
var deletePINCalled = false // track side effects
func verifyPINAndGetHash(issuer _: String, accountID _: String, pin _: String) -> String? {
return verifyResult
}
func setPIN(issuer _: String, accountID _: String, pin _: String, isAutoGenerated _: Bool) throws -> String {
return setPINResult
}
func deletePIN(issuer _: String, accountID _: String) throws {
deletePINCalled = true
}
// ... remaining protocol methods
}
Pattern: Use var resultProperty for controlling return values and var methodCalled = false booleans for verifying side effects.
Available iOS protocols for mocking
| Protocol | File | Purpose |
|---|---|---|
PINServiceProtocol |
PINServiceProtocol.swift |
PIN set/verify/delete/hash |
PINKeychainServiceProtocol |
PINKeychainService.swift |
Keychain secret storage |
PINCryptoPolicyProtocol |
PINCryptoPolicy.swift |
Salt/key/iteration config |
CommonCryptoWrapperProtocol |
CommonCryptoWrapper.swift |
PBKDF2 key derivation |
LAContextProtocol |
LAContext+Extensions.swift |
Biometric evaluation |
DeviceAuthServiceProtocol |
DeviceAuthService.swift |
Device authentication |
TokenStorageServiceProtocol |
TokenService.swift |
Token keychain storage |
KeyPairManagerProtocol |
KeyPairManager.swift |
Cryptographic key pairs |
Android — MockK
Use MockK's mockk<T>() for mocking classes and interfaces:
val mockPinService = mockk<PinService>()
every { mockPinService.validatePIN(any(), "1234") } returns true
every { mockPinService.hasPIN(any()) } returns true
val account = Account(id = "test", issuer = "https://idsit.gov.bc.ca", clientID = "client")
val result = account.verifyPIN("1234", mockPinService)
assertTrue(result.success)
For data classes (e.g., NativeAccount), test serialization round-trips with Gson directly — no mocking needed.
Test Patterns
Time-dependent tests (eg. PIN penalty logic)
The penalty system locks users out after failed PIN attempts. Both platforms accept an injectable "current time" parameter to make tests deterministic.
iOS: Pass verifyDate: parameter:
let start = Date()
for i in 0..<5 {
_ = account.verifyPIN("wrong", pinService: mock, verifyDate: start.addingTimeInterval(Double(i)))
}
// Advance past penalty before next batch
let afterPenalty = start.addingTimeInterval(65)
Android: Pass timestamp to verifyPIN and isServingPenalty:
val now = System.currentTimeMillis()
account.verifyPIN("wrong", mockPinService, now)
val penalty = account.isServingPenalty(now)
Important: When testing escalating penalties, you must advance time past each penalty tier before triggering the next. Calling verifyPIN while a penalty is active will return "locked" without incrementing the attempt counter.
Penalty tiers: 5 attempts → 1 min, 10 → 10 min, 15 → 1 hour, 20 → 1 day.
NSCoding / Serialization round-trips
iOS — Use NSKeyedArchiver / NSKeyedUnarchiver:
let data = try NSKeyedArchiver.archivedData(withRootObject: original, requiringSecureCoding: true)
let decoded = try NSKeyedUnarchiver.unarchivedObject(ofClass: Account.self, from: data)
XCTAssertEqual(decoded?.id, original.id)
Android — Use Gson:
val json = gson.toJson(original)
val restored = gson.fromJson(json, NativeAccount::class.java)
assertEquals(original.uuid, restored.uuid)
Test naming conventions
iOS: test{Behavior} in camelCase — e.g., testVerifyPINReturnsSuccessOnCorrectPIN
Android: Backtick-quoted descriptive names — e.g., `verifyPIN returns success when PIN is correct`
Helper factories
Android — Create a createAccount() helper with defaults to reduce boilerplate:
private fun createAccount(
id: String = "test-uuid",
issuer: String = "https://idsit.gov.bc.ca",
clientID: String = "test-client-id",
securityMethod: AccountSecurityMethod = AccountSecurityMethod.PIN_NO_DEVICE_AUTH,
): Account = Account(id = id, issuer = issuer, clientID = clientID, securityMethod = securityMethod)
Checklist for adding tests
- Identify the class/struct to test and which platform(s)
- Check if the source file is already in
Package.swiftsources:(iOS) — add if missing - Check if new dependencies need stubs in
SPMCompat.swift(iOS) - Create mock(s) for any protocol/interface dependencies
- Place test file in
ios/BcscCoreTests/orandroid/src/test/java/com/bcsccore/{subpackage}/ - For time-dependent logic, use injectable timestamps rather than
Date()/System.currentTimeMillis() - Run
yarn testand verify all tests pass on both platforms
Source: bcgov/bc-wallet-mobile — distributed by TomeVault.
Decide Fit First
Design Intent
How To Use It
Boundaries And Review