blob: 45b814f12ca480e0dd6266becd901e4e9731c3fb [file]
// Copyright 2026 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::{
collections::{HashMap, HashSet},
sync::Mutex,
};
use attr::{Attr, LabelOrFile};
use rule::FrozenRule;
use starlark::{environment::FrozenModule, values::FrozenValueTyped};
use testutils::{Assert, FakeEvalContext, FakeTarget};
use types::{Label, OutputType, PackageRef, Session};
fn new_assert() -> Assert {
Assert::new_rule_assert()
}
#[test]
fn test_pure_rule_inheritance() {
let mut assert = new_assert();
let native = assert.load_module("//rules:native.scl");
let pure = assert.load_module("//rules:pure.scl");
let rule = |module: &FrozenModule, name: &str| {
let val = module.get(name).unwrap().value().unpack_frozen().unwrap();
let typed = FrozenValueTyped::<FrozenRule<FakeEvalContext>>::new(val).unwrap();
Some(typed.as_ref())
};
assert.pass(
r#"
load("//rules:pure.scl", "child_rule", "parent_rule")
load("//rules:native.scl", "custom_shared_library", "static_library")
custom_shared_library(
name = "shared_library",
mandatory = "mandatory_val",
optional = "optional_val",
unknown = "unknown",
)
static_library(
name = "static_library",
optional = "optional_val",
unknown = "unknown"
)
parent_rule(
name = "parent_defaulted",
parent_only = "p",
)
child_rule(
name = "child_defaulted",
parent_only = "p",
child_only = "c",
)
child_rule(
name = "child_override",
parent_only = "parent_val",
child_only = "child_val",
override = "//:custom_val",
)
"#,
);
let heap = starlark::values::FrozenHeap::new();
let mut unknown_attrs = HashMap::new();
unknown_attrs.insert(
"unknown".to_owned(),
starlark::values::Value::new_frozen(heap.alloc("unknown")),
);
let context = assert.context();
let load = |name: &str| {
let label = Label::new(PackageRef::root().to_owned(), name.to_owned());
context
.session
.get_target(label.as_ref(), context.session.default_toolchain.as_ref())
};
assert_eq!(
*load("shared_library"),
FakeTarget {
label: Label::new(PackageRef::root().to_owned(), "shared_library".to_owned()),
toolchain: context.session.default_toolchain.clone(),
outputs: vec![],
attrs: vec![
Attr::String("optional_val".to_owned()),
Attr::String("mandatory_val".to_owned()),
],
output_type: Some(OutputType::SharedLibrary),
rule: rule(&native, "custom_shared_library"),
cxx_attrs: unknown_attrs.clone(),
dependencies: Mutex::new(HashSet::new()),
}
);
assert_eq!(
*load("static_library"),
FakeTarget {
label: Label::new(PackageRef::root().to_owned(), "static_library".to_owned()),
toolchain: context.session.default_toolchain.clone(),
outputs: vec![],
attrs: vec![Attr::String("optional_val".to_owned())],
output_type: Some(OutputType::StaticLibrary),
rule: rule(&native, "static_library"),
cxx_attrs: unknown_attrs.clone(),
dependencies: Mutex::new(HashSet::new()),
}
);
let toolchain = Label::new(
PackageRef::root().to_owned(),
"default_toolchain".to_owned(),
);
assert_eq!(
*load("parent_defaulted"),
FakeTarget {
label: Label::new(PackageRef::root().to_owned(), "parent_defaulted".to_owned()),
toolchain: toolchain.clone(),
outputs: vec![],
attrs: vec![
Attr::String("p".to_owned()),
Attr::Label(Some(LabelOrFile::Label(Label::new(
PackageRef::root().to_owned(),
"parent".to_owned()
)))),
],
output_type: None,
rule: rule(&pure, "parent_rule"),
cxx_attrs: HashMap::new(),
dependencies: Mutex::new(HashSet::from([(
Label::new(PackageRef::root().to_owned(), "parent".to_owned()),
toolchain.clone(),
)])),
}
);
assert_eq!(
*load("child_defaulted"),
FakeTarget {
label: Label::new(PackageRef::root().to_owned(), "child_defaulted".to_owned()),
toolchain: toolchain.clone(),
outputs: vec![],
attrs: vec![
Attr::String("p".to_owned()),
Attr::Label(Some(LabelOrFile::Label(Label::new(
PackageRef::root().to_owned(),
"child".to_owned()
)))),
Attr::String("c".to_owned()),
],
output_type: None,
rule: rule(&pure, "child_rule"),
cxx_attrs: HashMap::new(),
dependencies: Mutex::new(HashSet::from([(
Label::new(PackageRef::root().to_owned(), "child".to_owned()),
toolchain.clone(),
)])),
}
);
assert_eq!(
*load("child_override"),
FakeTarget {
label: Label::new(PackageRef::root().to_owned(), "child_override".to_owned()),
toolchain: toolchain.clone(),
outputs: vec![],
attrs: vec![
Attr::String("parent_val".to_owned()),
Attr::Label(Some(LabelOrFile::Label(Label::new(
PackageRef::root().to_owned(),
"custom_val".to_owned()
)))),
Attr::String("child_val".to_owned()),
],
output_type: None,
rule: rule(&pure, "child_rule"),
cxx_attrs: HashMap::new(),
dependencies: Mutex::new(HashSet::from([(
Label::new(PackageRef::root().to_owned(), "custom_val".to_owned()),
toolchain.clone(),
)])),
}
);
}