use crate::api::test_helpers::create_test_quantized_model;
use crate::gguf::{ArchConstraints, GGUFConfig, OwnedQuantizedModel, OwnedQuantizedModelCuda};
fn model(architecture: &str) -> OwnedQuantizedModel {
let config = GGUFConfig {
architecture: architecture.to_string(),
constraints: ArchConstraints::from_architecture(architecture),
hidden_dim: 64,
intermediate_dim: 128,
num_layers: 1,
num_heads: 4,
num_kv_heads: 4,
vocab_size: 256,
context_length: 128,
rope_theta: 10000.0,
eps: 1e-5,
rope_type: 0,
explicit_head_dim: None,
query_pre_attn_scalar: None,
bos_token_id: None,
eos_token_id: None,
};
create_test_quantized_model(&config)
}
#[test]
fn the_dense_constructors_refuse_a_moe_model_by_name() {
for arch in ["qwen3moe", "qwen3_moe", "qwen35moe"] {
let m = model(arch);
let err = OwnedQuantizedModelCuda::with_max_seq_len(m, 0, 64)
.err()
.unwrap_or_else(|| panic!("{arch}: a MoE model was accepted by the dense constructor"));
let msg = err.to_string();
assert!(msg.contains("Mixture-of-Experts"), "{arch}: {msg}");
assert!(
msg.contains(arch),
"{arch}: the refusal must name the model: {msg}"
);
assert!(
msg.contains("apr run"),
"{arch}: the refusal must name the route: {msg}"
);
assert_eq!(err.into_model().config().architecture, arch);
let msg = OwnedQuantizedModelCuda::new(model(arch), 0)
.err()
.expect("`new` delegates to the same gate")
.to_string();
assert!(msg.contains("Mixture-of-Experts"), "{arch} via new: {msg}");
}
}
#[test]
fn a_dense_model_is_not_refused_as_moe() {
let m = model("llama");
assert!(!m.config().constraints.is_moe);
if let Err(e) = OwnedQuantizedModelCuda::with_max_seq_len(m, 0, 64) {
assert!(
!e.to_string().contains("Mixture-of-Experts"),
"a dense model was refused as MoE: {e}"
);
}
}
#[test]
fn the_moe_refusal_runs_before_cuda_init_and_upload() {
let src = include_str!("mod.rs");
let body = src
.split("pub fn with_max_seq_len(")
.nth(1)
.and_then(|t| t.split("\n }\n").next())
.expect("with_max_seq_len body");
let check = body
.find("Self::check_not_moe(model)")
.expect("with_max_seq_len calls check_not_moe");
let build = body
.find("Self::build(")
.expect("with_max_seq_len delegates to build");
assert!(check < build, "check_not_moe must run before build: {body}");
assert!(
!body.contains("CudaExecutor::new"),
"no CUDA init before the check: {body}"
);
let build_body = src.split("fn build(").nth(1).expect("build body");
assert!(build_body.contains("CudaExecutor::new("));
let new_body = src
.split("pub fn new(model: OwnedQuantizedModel")
.nth(1)
.expect("new");
let new_body = new_body.split("\n }\n").next().expect("new body");
assert!(
new_body.contains("Self::with_max_seq_len("),
"`new` must delegate to the gate: {new_body}"
);
}