#![allow(dead_code)]
#[path = "../../../../../tests/support/rust_locks.rs"]
pub mod locks;
use std::collections::{BTreeMap, BTreeSet};
use std::env;
use std::fs;
use std::net::TcpListener;
use std::path::{Component, Path, PathBuf};
use std::process::{Command, Output};
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::{SystemTime, UNIX_EPOCH};
use serde_json::Value;
use sha2::{Digest, Sha256};
use type_bridge_contract::capability::{CapabilityId, CapabilitySet};
use type_bridge_contract::codec::to_canonical_json;
use type_bridge_contract::fingerprint::SemanticProfileId;
use type_bridge_contract::managed_scope::ManagedScopeId;
use type_bridge_contract::projection::{BindingTarget, ProjectionConfig, RuntimeProjection};
use type_bridge_contract::schema::{DeclaredSchema, DocumentId};
use type_bridge_schema::{
BUILTIN_SCHEMA_CAPABILITY_IDS, ManagedDeltaContext, SchemaDocumentSet, VerifiedSchemaAuthority,
build_schema_authority, normalize_documents, project, resolve,
};
use type_bridge_schema_codegen::{GeneratedPackage, RustEmitter};
pub const TEST_PROFILE: &str = "typedb-3.12.1/v1";
pub const TEST_SCOPE: &str = "schema-codegen-acceptance";
pub const SDK_V2_PROOF_SCHEMA: &str =
"tests/contracts/sdk_conformance/sdk-v2/proof-fragment-schema-v1.json";
pub const SDK_V2_PROOF_ALLOWLIST: &str =
"tests/contracts/sdk_conformance/sdk-v2/proof-fragment-allowlist-v1.json";
pub const SDK_V2_JOURNEY: &str = "tests/contracts/sdk_conformance/sdk-v2/journey-v2.json";
const SDK_V2_PROOF_FORMAT: &str = "typebridge.sdk-v2-proof-fragment/v1";
const SDK_V2_ALLOWLIST_FORMAT: &str = "typebridge.sdk-v2-proof-fragment-allowlist/v1";
const SDK_V2_PROOF_MAX_BYTES: u64 = 64 * 1024;
const SDK_V2_PROOF_MAX_RESULTS: usize = 16;
const SDK_V2_PROOF_MAX_SOURCES: usize = 16;
pub type SdkV2ProofLane = (String, String);
#[derive(Clone, Debug, Eq, PartialEq)]
struct SdkV2ProofProducerAuthority {
sources: Vec<String>,
results: BTreeMap<SdkV2ProofLane, String>,
}
fn proof_object<'a>(
value: &'a Value,
expected: &[&str],
context: &str,
) -> Result<&'a serde_json::Map<String, Value>, String> {
let object = value
.as_object()
.ok_or_else(|| format!("{context} must be an object"))?;
let actual = object.keys().map(String::as_str).collect::<BTreeSet<_>>();
let expected = expected.iter().copied().collect::<BTreeSet<_>>();
if actual != expected {
return Err(format!(
"{context} fields differ: expected {expected:?}, got {actual:?}"
));
}
Ok(object)
}
fn proof_string<'a>(value: &'a Value, context: &str) -> Result<&'a str, String> {
value
.as_str()
.filter(|value| !value.is_empty())
.ok_or_else(|| format!("{context} must be nonempty text"))
}
fn is_lower_hex_64(value: &str) -> bool {
value.len() == 64
&& value
.bytes()
.all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte))
}
fn is_identifier(value: &str, first: impl Fn(u8) -> bool, rest: impl Fn(u8) -> bool) -> bool {
let mut bytes = value.bytes();
bytes.next().is_some_and(&first) && bytes.all(rest)
}
fn proof_relative_path(value: &str, context: &str) -> Result<PathBuf, String> {
if value.is_empty()
|| value.len() > 512
|| value.contains('\\')
|| !value
.bytes()
.all(|byte| byte.is_ascii_alphanumeric() || b"._-/".contains(&byte))
{
return Err(format!("{context} is not a portable source path"));
}
let path = PathBuf::from(value);
if path.is_absolute()
|| path
.components()
.any(|component| !matches!(component, Component::Normal(_)))
|| path.to_string_lossy() != value
{
return Err(format!("{context} is not a canonical relative source path"));
}
Ok(path)
}
fn proof_regular_source(root: &Path, relative: &str, context: &str) -> Result<Vec<u8>, String> {
let relative_path = proof_relative_path(relative, context)?;
let mut current = root.to_path_buf();
for component in relative_path.components() {
let Component::Normal(component) = component else {
return Err(format!("{context} is not a canonical relative source path"));
};
current.push(component);
let metadata = fs::symlink_metadata(¤t)
.map_err(|error| format!("{context} is not inspectable: {error}"))?;
if metadata.file_type().is_symlink() {
return Err(format!("{context} traverses a symlink"));
}
}
let metadata = fs::metadata(¤t)
.map_err(|error| format!("{context} metadata is not readable: {error}"))?;
if !metadata.is_file() {
return Err(format!("{context} must be a regular file"));
}
fs::read(¤t).map_err(|error| format!("{context} is not readable: {error}"))
}
pub fn sdk_v2_source_identity(root: &Path, relative: &str) -> Result<Value, String> {
let bytes = proof_regular_source(root, relative, "proof source")?;
Ok(serde_json::json!({
"path": relative,
"sha256": format!("{:x}", Sha256::digest(bytes)),
}))
}
fn validate_proof_source_identity(
root: &Path,
value: &Value,
context: &str,
) -> Result<Value, String> {
let identity = proof_object(value, &["path", "sha256"], context)?;
let relative = proof_string(&identity["path"], &format!("{context}.path"))?;
let digest = proof_string(&identity["sha256"], &format!("{context}.sha256"))?;
if !is_lower_hex_64(digest) {
return Err(format!("{context}.sha256 is not lowercase SHA-256"));
}
let expected = sdk_v2_source_identity(root, relative)?;
if value != &expected {
return Err(format!("{context} digest does not match {relative}"));
}
Ok(expected)
}
fn proof_lane(value: &Value, context: &str) -> Result<SdkV2ProofLane, String> {
let lane = proof_object(value, &["observation_ref", "proof_kind"], context)?;
let observation_ref = proof_string(&lane["observation_ref"], context)?;
let proof_kind = proof_string(&lane["proof_kind"], context)?;
if !is_identifier(
observation_ref,
|byte| byte.is_ascii_lowercase(),
|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit() || byte == b'_',
) || !matches!(
proof_kind,
"direct_runtime" | "remote_runtime" | "diagnostic" | "lifecycle"
) {
return Err(format!("{context} is not a valid observation lane"));
}
Ok((observation_ref.to_owned(), proof_kind.to_owned()))
}
fn sdk_v2_proof_authority(
root: &Path,
binding: &str,
) -> Result<BTreeMap<String, SdkV2ProofProducerAuthority>, String> {
if !matches!(binding, "python" | "node" | "rust" | "c") {
return Err(format!("unknown sdk-v2 binding {binding:?}"));
}
let raw = proof_regular_source(root, SDK_V2_PROOF_ALLOWLIST, "sdk-v2 proof allowlist")?;
let value: Value = serde_json::from_slice(&raw)
.map_err(|error| format!("sdk-v2 proof allowlist is invalid JSON: {error}"))?;
let allowlist = proof_object(
&value,
&["format", "semantic_profile", "bindings"],
"allowlist",
)?;
if proof_string(&allowlist["format"], "allowlist format")? != SDK_V2_ALLOWLIST_FORMAT
|| proof_string(&allowlist["semantic_profile"], "allowlist profile")? != TEST_PROFILE
{
return Err("sdk-v2 proof allowlist authority is not v1".to_owned());
}
let bindings = proof_object(
&allowlist["bindings"],
&["python", "node", "rust", "c"],
"allowlist bindings",
)?;
let producers = bindings[binding]
.as_array()
.filter(|values| !values.is_empty())
.ok_or_else(|| format!("{binding} proof allowlist is empty or malformed"))?;
let mut authority = BTreeMap::new();
let mut ordered_producers = Vec::with_capacity(producers.len());
let mut claimed_lanes = BTreeSet::new();
for (producer_index, producer) in producers.iter().enumerate() {
let producer = proof_object(
producer,
&["id", "results", "sources"],
&format!("allowlist producer[{producer_index}]"),
)?;
let producer_id = proof_string(
&producer["id"],
&format!("allowlist producer[{producer_index}].id"),
)?;
if producer_id.len() > 128
|| !is_identifier(
producer_id,
|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit(),
|byte| {
byte.is_ascii_lowercase()
|| byte.is_ascii_digit()
|| matches!(byte, b'.' | b'_' | b'-')
},
)
{
return Err("sdk-v2 proof allowlist producer ID is invalid".to_owned());
}
let sources = producer["sources"]
.as_array()
.filter(|sources| !sources.is_empty() && sources.len() <= SDK_V2_PROOF_MAX_SOURCES)
.ok_or_else(|| "proof allowlist producer must bind 1..16 sources".to_owned())?;
let mut source_paths = Vec::with_capacity(sources.len());
for (source_index, source) in sources.iter().enumerate() {
let source = proof_string(
source,
&format!("allowlist producer[{producer_index}].sources[{source_index}]"),
)?;
proof_relative_path(source, "proof allowlist producer source")?;
source_paths.push(source.to_owned());
}
if !source_paths.windows(2).all(|pair| pair[0] < pair[1]) {
return Err(
"proof allowlist producer sources are not unique and path-sorted".to_owned(),
);
}
let results = producer["results"]
.as_array()
.filter(|results| !results.is_empty() && results.len() <= SDK_V2_PROOF_MAX_RESULTS)
.ok_or_else(|| "proof allowlist producer must own 1..16 results".to_owned())?;
let mut result_authority = BTreeMap::new();
let mut ordered_lanes = Vec::with_capacity(results.len());
for (result_index, result) in results.iter().enumerate() {
let result = proof_object(
result,
&["observation_ref", "proof_kind", "test_id"],
&format!("allowlist producer[{producer_index}].results[{result_index}]"),
)?;
let lane = proof_lane(
&serde_json::json!({
"observation_ref": result["observation_ref"],
"proof_kind": result["proof_kind"],
}),
&format!("allowlist producer[{producer_index}].results[{result_index}]"),
)?;
let test_id = proof_string(
&result["test_id"],
&format!("allowlist producer[{producer_index}].results[{result_index}].test_id"),
)?;
if test_id.len() > 192
|| !is_identifier(
test_id,
|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit(),
|byte| {
byte.is_ascii_lowercase()
|| byte.is_ascii_digit()
|| matches!(byte, b'.' | b'_' | b':' | b'-')
},
)
{
return Err("sdk-v2 proof allowlist test ID is invalid".to_owned());
}
if !claimed_lanes.insert(lane.clone()) {
return Err("sdk-v2 proof allowlist lane is claimed twice".to_owned());
}
result_authority.insert(lane.clone(), test_id.to_owned());
ordered_lanes.push(lane);
}
if !ordered_lanes.windows(2).all(|pair| pair[0] < pair[1]) {
return Err("proof allowlist producer results are not unique and sorted".to_owned());
}
if authority
.insert(
producer_id.to_owned(),
SdkV2ProofProducerAuthority {
sources: source_paths,
results: result_authority,
},
)
.is_some()
{
return Err("sdk-v2 proof allowlist producer ID is duplicated".to_owned());
}
ordered_producers.push(producer_id.to_owned());
}
if !ordered_producers.windows(2).all(|pair| pair[0] < pair[1]) {
return Err(format!(
"{binding} proof allowlist producers are not unique and sorted"
));
}
Ok(authority)
}
pub fn sdk_v2_proof_lanes(root: &Path, binding: &str) -> Result<BTreeSet<SdkV2ProofLane>, String> {
Ok(sdk_v2_proof_authority(root, binding)?
.values()
.flat_map(|producer| producer.results.keys().cloned())
.collect())
}
fn load_proof_fragment(path: &Path) -> Result<Value, String> {
if !path.is_absolute()
|| path
.components()
.any(|component| matches!(component, Component::CurDir | Component::ParentDir))
{
return Err(format!(
"proof fragment {} must use a normalized absolute path",
path.display()
));
}
let mut chain = path.ancestors().collect::<Vec<_>>();
chain.reverse();
let mut metadata = None;
for component in chain {
let component_metadata = fs::symlink_metadata(component).map_err(|error| {
format!(
"proof fragment {} is not inspectable: {error}",
path.display()
)
})?;
if component_metadata.file_type().is_symlink() {
return Err(format!(
"proof fragment {} traverses a symlink",
path.display()
));
}
metadata = Some(component_metadata);
}
let metadata =
metadata.ok_or_else(|| format!("proof fragment {} is not inspectable", path.display()))?;
if !metadata.is_file() {
return Err(format!(
"proof fragment {} must be a regular non-symlink file",
path.display()
));
}
if metadata.len() > SDK_V2_PROOF_MAX_BYTES {
return Err(format!(
"proof fragment {} exceeds {} bytes",
path.display(),
SDK_V2_PROOF_MAX_BYTES
));
}
let raw = fs::read(path)
.map_err(|error| format!("proof fragment {} is not readable: {error}", path.display()))?;
let value: Value = serde_json::from_slice(&raw)
.map_err(|error| format!("proof fragment {} is invalid JSON: {error}", path.display()))?;
let mut canonical = to_canonical_json(&value)
.map_err(|_| "proof fragment cannot be canonicalized".to_owned())?;
canonical.push(b'\n');
if raw != canonical {
return Err(format!(
"proof fragment {} is not compact canonical JSON plus one LF",
path.display()
));
}
Ok(value)
}
pub fn sdk_v2_proof_paths(value: &std::ffi::OsStr) -> Result<Vec<PathBuf>, String> {
let paths = std::env::split_paths(value).collect::<Vec<_>>();
if paths.is_empty() || paths.iter().any(|path| path.as_os_str().is_empty()) {
return Err("sdk-v2 proof fragment path list is empty or malformed".to_owned());
}
Ok(paths)
}
pub fn validate_sdk_v2_proof_fragments(
root: &Path,
binding: &str,
run_nonce: &str,
fragment_paths: &[PathBuf],
) -> Result<BTreeMap<SdkV2ProofLane, Value>, String> {
if !is_lower_hex_64(run_nonce) {
return Err("sdk-v2 proof run nonce must be 64 lowercase hex characters".to_owned());
}
if fragment_paths.is_empty() {
return Err("at least one sdk-v2 proof fragment is required".to_owned());
}
let producer_authority = sdk_v2_proof_authority(root, binding)?;
let allowed = producer_authority
.values()
.flat_map(|producer| producer.results.keys().cloned())
.collect::<BTreeSet<_>>();
let expected_contract = serde_json::json!({
"allowlist": sdk_v2_source_identity(root, SDK_V2_PROOF_ALLOWLIST)?,
"journey": sdk_v2_source_identity(root, SDK_V2_JOURNEY)?,
"proof_schema": sdk_v2_source_identity(root, SDK_V2_PROOF_SCHEMA)?,
});
let mut normalized_paths = BTreeSet::new();
let mut producer_ids = BTreeSet::new();
let mut observations = BTreeMap::new();
for path in fragment_paths {
let normalized = path.canonicalize().map_err(|error| {
format!(
"proof fragment {} cannot be resolved: {error}",
path.display()
)
})?;
if !normalized_paths.insert(normalized) {
return Err("one sdk-v2 proof fragment path was supplied twice".to_owned());
}
let fragment = load_proof_fragment(path)?;
let fragment = proof_object(
&fragment,
&[
"format",
"binding",
"semantic_profile",
"run_nonce",
"contract",
"producer",
"results",
],
"proof fragment",
)?;
if proof_string(&fragment["format"], "proof fragment format")? != SDK_V2_PROOF_FORMAT
|| proof_string(&fragment["semantic_profile"], "proof fragment profile")?
!= TEST_PROFILE
{
return Err("proof fragment format/profile is not sdk-v2 v1".to_owned());
}
if proof_string(&fragment["binding"], "proof fragment binding")? != binding {
return Err("proof fragment belongs to another binding".to_owned());
}
if proof_string(&fragment["run_nonce"], "proof fragment run nonce")? != run_nonce {
return Err("proof fragment belongs to another run".to_owned());
}
let contract = proof_object(
&fragment["contract"],
&["allowlist", "journey", "proof_schema"],
"proof fragment contract",
)?;
for (name, identity) in contract {
validate_proof_source_identity(root, identity, &format!("contract.{name}"))?;
}
if fragment["contract"] != expected_contract {
return Err("proof fragment binds another sdk-v2 contract".to_owned());
}
let producer = proof_object(&fragment["producer"], &["id", "sources"], "producer")?;
let producer_id = proof_string(&producer["id"], "producer.id")?;
if producer_id.len() > 128
|| !is_identifier(
producer_id,
|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit(),
|byte| {
byte.is_ascii_lowercase()
|| byte.is_ascii_digit()
|| matches!(byte, b'.' | b'_' | b'-')
},
)
{
return Err("proof fragment producer ID is invalid".to_owned());
}
if !producer_ids.insert(producer_id.to_owned()) {
return Err(format!("proof producer {producer_id:?} emitted twice"));
}
let authority = producer_authority
.get(producer_id)
.ok_or_else(|| format!("proof producer {producer_id:?} is not committed"))?;
let sources = producer["sources"]
.as_array()
.filter(|sources| !sources.is_empty() && sources.len() <= SDK_V2_PROOF_MAX_SOURCES)
.ok_or_else(|| "proof producer must bind 1..16 sources".to_owned())?;
let mut source_paths = Vec::with_capacity(sources.len());
for (index, source) in sources.iter().enumerate() {
let validated = validate_proof_source_identity(
root,
source,
&format!("producer.sources[{index}]"),
)?;
source_paths.push(proof_string(&validated["path"], "producer source path")?.to_owned());
}
if !source_paths.windows(2).all(|pair| pair[0] < pair[1]) {
return Err("proof producer sources are not unique and path-sorted".to_owned());
}
if source_paths != authority.sources {
return Err(format!(
"proof producer {producer_id:?} source paths differ from committed authority"
));
}
let results = fragment["results"]
.as_array()
.filter(|results| !results.is_empty() && results.len() <= SDK_V2_PROOF_MAX_RESULTS)
.ok_or_else(|| "proof fragment must carry 1..16 results".to_owned())?;
let mut result_lanes = Vec::with_capacity(results.len());
for (index, result) in results.iter().enumerate() {
let result = proof_object(
result,
&[
"observation_ref",
"proof_kind",
"test_id",
"outcome",
"observation",
],
&format!("results[{index}]"),
)?;
let lane = proof_lane(
&serde_json::json!({
"observation_ref": result["observation_ref"],
"proof_kind": result["proof_kind"],
}),
&format!("results[{index}]"),
)?;
let test_id = proof_string(&result["test_id"], &format!("results[{index}].test_id"))?;
if test_id.len() > 192
|| !is_identifier(
test_id,
|byte| byte.is_ascii_lowercase() || byte.is_ascii_digit(),
|byte| {
byte.is_ascii_lowercase()
|| byte.is_ascii_digit()
|| matches!(byte, b'.' | b'_' | b':' | b'-')
},
)
{
return Err(format!("results[{index}] test ID is invalid"));
}
if proof_string(&result["outcome"], &format!("results[{index}].outcome"))? != "passed"
|| !result["observation"].is_object()
{
return Err(format!(
"results[{index}] is not a passed object observation"
));
}
if !allowed.contains(&lane) {
return Err(format!("proof fragment carries unexpected lane {lane:?}"));
}
let expected_test_id = authority.results.get(&lane).ok_or_else(|| {
format!("proof producer {producer_id:?} does not own lane {lane:?}")
})?;
if test_id != expected_test_id {
return Err(format!(
"proof producer {producer_id:?} lane {lane:?} has the wrong test ID"
));
}
if observations
.insert(lane.clone(), result["observation"].clone())
.is_some()
{
return Err(format!("proof lane {lane:?} was emitted twice"));
}
result_lanes.push(lane);
}
if !result_lanes.windows(2).all(|pair| pair[0] < pair[1]) {
return Err("proof fragment results are not unique and lane-sorted".to_owned());
}
if result_lanes.iter().cloned().collect::<BTreeSet<_>>()
!= authority.results.keys().cloned().collect()
{
return Err(format!(
"proof producer {producer_id:?} did not emit its exact committed lanes"
));
}
}
if observations.keys().cloned().collect::<BTreeSet<_>>() != allowed {
return Err("proof fragment lane coverage differs from committed allowlist".to_owned());
}
if producer_ids != producer_authority.keys().cloned().collect() {
return Err("proof fragments did not cover every committed producer".to_owned());
}
Ok(observations)
}
pub fn declared(source: &str) -> DeclaredSchema {
let documents = SchemaDocumentSet::parse([(
DocumentId::new("schema-codegen-authority.yaml").expect("test document ID"),
source,
)])
.expect("test authority source parses");
normalize_documents(&documents).expect("test authority source normalizes")
}
pub fn authority(source: &str) -> VerifiedSchemaAuthority {
authority_with(source, TEST_SCOPE, TEST_PROFILE)
}
pub fn authority_with(source: &str, scope: &str, profile: &str) -> VerifiedSchemaAuthority {
let declared = declared(source);
authority_for_declared(&declared, scope, profile)
}
pub fn authority_for_declared(
declared: &DeclaredSchema,
scope: &str,
profile: &str,
) -> VerifiedSchemaAuthority {
let available: CapabilitySet = BUILTIN_SCHEMA_CAPABILITY_IDS
.iter()
.map(|id| CapabilityId::new(*id).expect("built-in capability ID"))
.collect();
let context = ManagedDeltaContext::new(
ManagedScopeId::new(scope).expect("test managed scope"),
SemanticProfileId::new(profile).expect("test semantic profile"),
available,
);
build_schema_authority(declared, declared.required_capabilities(), &context)
.expect("test schema authority builds")
}
static STAGE_SEQUENCE: AtomicU64 = AtomicU64::new(0);
pub static CARGO_MUTEX: std::sync::Mutex<()> = std::sync::Mutex::new(());
pub struct Stage(PathBuf);
impl Stage {
pub fn new() -> Self {
let nonce = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("system time follows the Unix epoch")
.as_nanos();
Self::new_for_nonce(nonce)
}
pub fn new_for_nonce(nonce: u128) -> Self {
let sequence = STAGE_SEQUENCE.fetch_add(1, Ordering::Relaxed);
let path = env::temp_dir().join(format!(
"typebridge-codegen-{}-{nonce}-{sequence}",
std::process::id()
));
fs::create_dir(&path).expect("unique codegen acceptance stage creates");
Self(path)
}
pub fn path(&self) -> &Path {
&self.0
}
}
impl Drop for Stage {
fn drop(&mut self) {
let result = fs::remove_dir_all(&self.0);
if !std::thread::panicking() {
result.expect("codegen acceptance stage removes");
}
}
}
pub fn write_package(package: &GeneratedPackage, root: &Path) {
for (relative, contents) in package.files() {
let path = root.join(relative);
fs::create_dir_all(path.parent().expect("generated path has a parent"))
.expect("generated package directory creates");
fs::write(path, contents).expect("generated package file writes");
}
}
pub fn command_exists(program: &str) -> bool {
Command::new(program)
.arg("--version")
.output()
.is_ok_and(|output| output.status.success())
}
pub fn runtime_include() -> PathBuf {
let path = Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("schema-codegen belongs to the crate directory")
.join("c/include");
assert!(path.join("typebridge/type_bridge.h").is_file());
path
}
pub fn native_library() -> PathBuf {
let executable = env::current_exe().expect("current test executable is available");
let filename = format!(
"{}type_bridge_c{}",
env::consts::DLL_PREFIX,
env::consts::DLL_SUFFIX,
);
executable
.ancestors()
.flat_map(|directory| {
[
directory.join(&filename),
directory.join("deps").join(&filename),
]
})
.find(|candidate| candidate.is_file())
.expect("build type-bridge-c's shared library before the C live producer")
}
pub fn base64(bytes: &[u8]) -> String {
const ALPHABET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
let mut output = String::with_capacity(bytes.len().div_ceil(3) * 4);
for chunk in bytes.chunks(3) {
let first = chunk[0];
let second = chunk.get(1).copied().unwrap_or(0);
let third = chunk.get(2).copied().unwrap_or(0);
output.push(ALPHABET[(first >> 2) as usize] as char);
output.push(ALPHABET[(((first & 0x03) << 4) | (second >> 4)) as usize] as char);
if chunk.len() > 1 {
output.push(ALPHABET[(((second & 0x0f) << 2) | (third >> 6)) as usize] as char);
} else {
output.push('=');
}
if chunk.len() > 2 {
output.push(ALPHABET[(third & 0x3f) as usize] as char);
} else {
output.push('=');
}
}
output
}
pub fn free_port() -> u16 {
TcpListener::bind(("127.0.0.1", 0))
.expect("loopback port allocation succeeds")
.local_addr()
.expect("loopback local address is readable")
.port()
}
pub fn repository_root() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("schema-codegen has crates parent")
.parent()
.expect("crates has core parent")
.parent()
.expect("core has repository parent")
.canonicalize()
.expect("repository root canonicalizes")
}
pub fn cargo_target() -> PathBuf {
env::var_os("ACCEPTANCE_TARGET_DIR")
.map(PathBuf::from)
.unwrap_or_else(|| {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("schema-codegen has crates parent")
.parent()
.expect("crates has core parent")
.join("target/tmp_acceptance_target")
})
}
pub fn cargo_with_env(arguments: &[&str], environment: &[(&str, &std::ffi::OsStr)]) -> Output {
let _guard = CARGO_MUTEX.lock().unwrap();
let executable = env::var_os("CARGO").unwrap_or_else(|| "cargo".into());
let mut command = Command::new(executable);
command
.args(arguments)
.env("CARGO_TARGET_DIR", cargo_target());
for (name, value) in environment {
command.env(name, value);
}
command.output().unwrap()
}
pub fn rust_projection(source: &str, document: &str) -> RuntimeProjection {
let documents = SchemaDocumentSet::parse([(
DocumentId::new(document).expect("static document ID is canonical"),
source,
)])
.expect("Rust fixture schema parses");
let declared = normalize_documents(&documents).expect("Rust fixture schema normalizes");
let resolved = resolve(
&declared,
&SemanticProfileId::new("typedb-3.12.1/v1").expect("profile is canonical"),
)
.expect("Rust fixture schema resolves");
let emitter = RustEmitter::new();
let resources = emitter
.code_resources_for(&resolved)
.expect("Rust code resources resolve");
project(
&resolved,
BindingTarget::Rust,
&ProjectionConfig::rust(),
&emitter.generator_handlers_for(&resolved),
&resources,
)
.expect("Rust fixture projection builds")
}
pub fn authority_for(
source: &str,
document: &str,
scope: &str,
) -> (
type_bridge_schema::ResolvedSchema,
type_bridge_schema::VerifiedSchemaAuthority,
) {
let documents = SchemaDocumentSet::parse([(
DocumentId::new(document).expect("Projected document ID is valid"),
source,
)])
.expect("Projected schema parses");
let declared = normalize_documents(&documents).expect("Projected schema normalizes");
let profile = SemanticProfileId::new(TEST_PROFILE).expect("Projected profile is valid");
let resolved = resolve(&declared, &profile).expect("Projected schema resolves");
let authority = authority_for_declared(&declared, scope, TEST_PROFILE);
(resolved, authority)
}
pub fn compile_c_consumer(
producer: (&str, &str),
compiler: &str,
stage: &Path,
local: &Path,
foreign: &Path,
library: Option<&Path>,
) -> PathBuf {
let (name, contents) = producer;
let source = stage.join(format!("{name}-live-consumer.c"));
fs::write(&source, contents).expect("C live consumer stages");
let output = stage.join(format!("{name}-live-{compiler}"));
let mut command = Command::new(compiler);
command
.args([
"-std=c17",
"-O2",
"-Wall",
"-Wextra",
"-Werror",
"-pedantic-errors",
])
.arg("-I")
.arg(runtime_include())
.arg("-I")
.arg(local.join("include"))
.arg("-I")
.arg(foreign.join("include"))
.arg(local.join("src/models.c"))
.arg(foreign.join("src/models.c"))
.arg(&source);
if let Some(library) = library {
let directory = library.parent().expect("shared library has a parent");
command
.arg("-L")
.arg(directory)
.arg("-ltype_bridge_c")
.arg(format!("-Wl,-rpath,{}", directory.display()))
.arg("-o")
.arg(&output);
} else {
command.args(["-fsyntax-only"]);
}
let compiled = command
.output()
.unwrap_or_else(|error| panic!("failed to launch {compiler}: {error}"));
assert!(
compiled.status.success(),
"{compiler} rejected the strict C17 {name} live producer:\nstdout:\n{}\nstderr:\n{}",
String::from_utf8_lossy(&compiled.stdout),
String::from_utf8_lossy(&compiled.stderr),
);
output
}