mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2025-02-07 20:46:06 +01:00
Start on Rust API tests
Does not currently work because every api struct is a static, yikes
This commit is contained in:
parent
ce8b56eee8
commit
f557afcaa1
8 changed files with 235 additions and 111 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1767,6 +1767,7 @@ dependencies = [
|
||||||
"image",
|
"image",
|
||||||
"nix",
|
"nix",
|
||||||
"pinnacle",
|
"pinnacle",
|
||||||
|
"pinnacle-api",
|
||||||
"pinnacle-api-defs",
|
"pinnacle-api-defs",
|
||||||
"prost",
|
"prost",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
@ -109,6 +109,7 @@ temp-env = "0.3.6"
|
||||||
tempfile = "3.10.1"
|
tempfile = "3.10.1"
|
||||||
test-log = { version = "0.2.15", default-features = false, features = ["trace"] }
|
test-log = { version = "0.2.15", default-features = false, features = ["trace"] }
|
||||||
pinnacle = { path = ".", features = ["testing"] }
|
pinnacle = { path = ".", features = ["testing"] }
|
||||||
|
pinnacle-api = { path = "./api/rust" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
testing = [
|
testing = [
|
||||||
|
|
|
@ -173,12 +173,10 @@ pub async fn connect(
|
||||||
let layout = LAYOUT.get_or_init(|| Layout::new(channel.clone()));
|
let layout = LAYOUT.get_or_init(|| Layout::new(channel.clone()));
|
||||||
let render = RENDER.get_or_init(|| Render::new(channel.clone()));
|
let render = RENDER.get_or_init(|| Render::new(channel.clone()));
|
||||||
|
|
||||||
SIGNAL
|
let _ = SIGNAL.set(RwLock::new(SignalState::new(
|
||||||
.set(RwLock::new(SignalState::new(
|
channel.clone(),
|
||||||
channel.clone(),
|
fut_sender.clone(),
|
||||||
fut_sender.clone(),
|
)));
|
||||||
)))
|
|
||||||
.map_err(|_| "failed to create SIGNAL")?;
|
|
||||||
|
|
||||||
let modules = ApiModules {
|
let modules = ApiModules {
|
||||||
pinnacle,
|
pinnacle,
|
||||||
|
|
|
@ -211,13 +211,17 @@ impl Output {
|
||||||
if setup.output.matches(output) {
|
if setup.output.matches(output) {
|
||||||
if let Some(OutputSetupLoc::Point(x, y)) = setup.loc {
|
if let Some(OutputSetupLoc::Point(x, y)) = setup.loc {
|
||||||
output.set_location(x, y);
|
output.set_location(x, y);
|
||||||
|
|
||||||
placed_outputs.insert(output.clone());
|
placed_outputs.insert(output.clone());
|
||||||
|
let props = output.props();
|
||||||
|
let x = props.x.unwrap();
|
||||||
|
let width = props.logical_width.unwrap() as i32;
|
||||||
if rightmost_output_and_x.is_none()
|
if rightmost_output_and_x.is_none()
|
||||||
|| rightmost_output_and_x
|
|| rightmost_output_and_x
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.is_some_and(|(_, rm_x)| x > *rm_x)
|
.is_some_and(|(_, rm_x)| x + width > *rm_x)
|
||||||
{
|
{
|
||||||
rightmost_output_and_x = Some((output.clone(), x));
|
rightmost_output_and_x = Some((output.clone(), x + width));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,16 +240,19 @@ impl Output {
|
||||||
output.set_loc_adj_to(rm_op, Alignment::RightAlignTop);
|
output.set_loc_adj_to(rm_op, Alignment::RightAlignTop);
|
||||||
} else {
|
} else {
|
||||||
output.set_location(0, 0);
|
output.set_location(0, 0);
|
||||||
|
println!("SET LOC FOR {} TO (0, 0)", output.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
placed_outputs.insert(output.clone());
|
placed_outputs.insert(output.clone());
|
||||||
let x = output.x().unwrap();
|
let props = output.props();
|
||||||
|
let x = props.x.unwrap();
|
||||||
|
let width = props.logical_width.unwrap() as i32;
|
||||||
if rightmost_output_and_x.is_none()
|
if rightmost_output_and_x.is_none()
|
||||||
|| rightmost_output_and_x
|
|| rightmost_output_and_x
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.is_some_and(|(_, rm_x)| x > *rm_x)
|
.is_some_and(|(_, rm_x)| x + width > *rm_x)
|
||||||
{
|
{
|
||||||
rightmost_output_and_x = Some((output.clone(), x));
|
rightmost_output_and_x = Some((output.clone(), x + width));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -272,36 +279,49 @@ impl Output {
|
||||||
output.set_loc_adj_to(relative_to, *alignment);
|
output.set_loc_adj_to(relative_to, *alignment);
|
||||||
|
|
||||||
placed_outputs.insert(output.clone());
|
placed_outputs.insert(output.clone());
|
||||||
let x = output.x().unwrap();
|
let props = output.props();
|
||||||
|
let x = props.x.unwrap();
|
||||||
|
let width = props.logical_width.unwrap() as i32;
|
||||||
if rightmost_output_and_x.is_none()
|
if rightmost_output_and_x.is_none()
|
||||||
|| rightmost_output_and_x
|
|| rightmost_output_and_x
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.is_some_and(|(_, rm_x)| x > *rm_x)
|
.is_some_and(|(_, rm_x)| x + width > *rm_x)
|
||||||
{
|
{
|
||||||
rightmost_output_and_x = Some((output.clone(), x));
|
rightmost_output_and_x = Some((output.clone(), x + width));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dbg!(&placed_outputs);
|
||||||
|
// dbg!(&outputs);
|
||||||
|
|
||||||
// Place all remaining outputs right of the rightmost one
|
// Place all remaining outputs right of the rightmost one
|
||||||
for output in outputs
|
for output in outputs
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|op| !placed_outputs.contains(op))
|
.filter(|op| {
|
||||||
|
// println!("CHECKING {}", op.name());
|
||||||
|
!placed_outputs.contains(op)
|
||||||
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
{
|
{
|
||||||
|
// println!("ATTEMPTING TO PLACE {}", output.name());
|
||||||
if let Some((rm_op, _)) = rightmost_output_and_x.as_ref() {
|
if let Some((rm_op, _)) = rightmost_output_and_x.as_ref() {
|
||||||
output.set_loc_adj_to(rm_op, Alignment::RightAlignTop);
|
output.set_loc_adj_to(rm_op, Alignment::RightAlignTop);
|
||||||
|
// println!("SET LOC FOR {} TO RIGHTMOST, REMAINING", output.name());
|
||||||
} else {
|
} else {
|
||||||
output.set_location(0, 0);
|
output.set_location(0, 0);
|
||||||
|
// println!("SET LOC FOR {} TO (0, 0), REMAINING", output.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
placed_outputs.insert(output.clone());
|
placed_outputs.insert(output.clone());
|
||||||
let x = output.x().unwrap();
|
let props = output.props();
|
||||||
|
let x = props.x.unwrap();
|
||||||
|
let width = props.logical_width.unwrap() as i32;
|
||||||
if rightmost_output_and_x.is_none()
|
if rightmost_output_and_x.is_none()
|
||||||
|| rightmost_output_and_x
|
|| rightmost_output_and_x
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.is_some_and(|(_, rm_x)| x > *rm_x)
|
.is_some_and(|(_, rm_x)| x + width > *rm_x)
|
||||||
{
|
{
|
||||||
rightmost_output_and_x = Some((output.clone(), x));
|
rightmost_output_and_x = Some((output.clone(), x + width));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -312,6 +332,7 @@ impl Output {
|
||||||
let layout_outputs_clone2 = layout_outputs.clone();
|
let layout_outputs_clone2 = layout_outputs.clone();
|
||||||
|
|
||||||
self.connect_signal(OutputSignal::Connect(Box::new(move |output| {
|
self.connect_signal(OutputSignal::Connect(Box::new(move |output| {
|
||||||
|
println!("GOT CONNECTION FOR OUTPUT {}", output.name());
|
||||||
apply_all_but_loc(output);
|
apply_all_but_loc(output);
|
||||||
layout_outputs_clone2();
|
layout_outputs_clone2();
|
||||||
})));
|
})));
|
||||||
|
|
|
@ -70,6 +70,7 @@ macro_rules! signals {
|
||||||
|
|
||||||
callback_sender
|
callback_sender
|
||||||
.send((self.current_id, callback))
|
.send((self.current_id, callback))
|
||||||
|
.map_err(|e| { println!("{e}"); e })
|
||||||
.expect("failed to send callback");
|
.expect("failed to send callback");
|
||||||
|
|
||||||
let handle = SignalHandle::new(self.current_id, remove_callback_sender);
|
let handle = SignalHandle::new(self.current_id, remove_callback_sender);
|
||||||
|
|
76
tests/common/mod.rs
Normal file
76
tests/common/mod.rs
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
use std::{panic::UnwindSafe, time::Duration};
|
||||||
|
|
||||||
|
use pinnacle::{backend::dummy::setup_dummy, state::State};
|
||||||
|
use smithay::reexports::calloop::{
|
||||||
|
self,
|
||||||
|
channel::{Event, Sender},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
pub fn with_state(
|
||||||
|
sender: &Sender<Box<dyn FnOnce(&mut State) + Send>>,
|
||||||
|
with_state: impl FnOnce(&mut State) + Send + 'static,
|
||||||
|
) {
|
||||||
|
sender.send(Box::new(with_state)).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sleep_secs(secs: u64) {
|
||||||
|
std::thread::sleep(Duration::from_secs(secs));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn test_api(
|
||||||
|
test: impl FnOnce(Sender<Box<dyn FnOnce(&mut State) + Send>>) + Send + UnwindSafe + 'static,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
let (mut state, mut event_loop) = setup_dummy(true, None)?;
|
||||||
|
|
||||||
|
let (sender, recv) = calloop::channel::channel::<Box<dyn FnOnce(&mut State) + Send>>();
|
||||||
|
|
||||||
|
event_loop
|
||||||
|
.handle()
|
||||||
|
.insert_source(recv, |event, _, state| match event {
|
||||||
|
Event::Msg(f) => f(state),
|
||||||
|
Event::Closed => (),
|
||||||
|
})
|
||||||
|
.map_err(|_| anyhow::anyhow!("failed to insert source"))?;
|
||||||
|
|
||||||
|
let tempdir = tempfile::tempdir()?;
|
||||||
|
|
||||||
|
state.start_grpc_server(tempdir.path())?;
|
||||||
|
|
||||||
|
let loop_signal = event_loop.get_signal();
|
||||||
|
|
||||||
|
let join_handle = std::thread::spawn(move || {
|
||||||
|
let res = std::panic::catch_unwind(|| {
|
||||||
|
test(sender);
|
||||||
|
});
|
||||||
|
loop_signal.stop();
|
||||||
|
if let Err(err) = res {
|
||||||
|
std::panic::resume_unwind(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
event_loop.run(None, &mut state, |state| {
|
||||||
|
state.fixup_z_layering();
|
||||||
|
state.space.refresh();
|
||||||
|
state.popup_manager.cleanup();
|
||||||
|
|
||||||
|
state
|
||||||
|
.display_handle
|
||||||
|
.flush_clients()
|
||||||
|
.expect("failed to flush client buffers");
|
||||||
|
|
||||||
|
// TODO: couple these or something, this is really error-prone
|
||||||
|
assert_eq!(
|
||||||
|
state.windows.len(),
|
||||||
|
state.z_index_stack.len(),
|
||||||
|
"Length of `windows` and `z_index_stack` are different. \
|
||||||
|
If you see this, report it to the developer."
|
||||||
|
);
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if let Err(err) = join_handle.join() {
|
||||||
|
panic!("{err:?}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
112
tests/lua_api.rs
112
tests/lua_api.rs
|
@ -1,19 +1,13 @@
|
||||||
|
mod common;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
io::Write,
|
io::Write,
|
||||||
panic::UnwindSafe,
|
|
||||||
process::{Command, Stdio},
|
process::{Command, Stdio},
|
||||||
time::Duration,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use pinnacle::{
|
use crate::common::{sleep_secs, test_api, with_state};
|
||||||
backend::dummy::setup_dummy,
|
|
||||||
state::{State, WithState},
|
|
||||||
};
|
|
||||||
use smithay::reexports::calloop::{
|
|
||||||
self,
|
|
||||||
channel::{Event, Sender},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
use pinnacle::state::WithState;
|
||||||
use test_log::test;
|
use test_log::test;
|
||||||
|
|
||||||
fn run_lua(ident: &str, code: &str) {
|
fn run_lua(ident: &str, code: &str) {
|
||||||
|
@ -93,18 +87,6 @@ fn setup_lua(ident: &str, code: &str) -> SetupLuaGuard {
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
fn with_state(
|
|
||||||
sender: &Sender<Box<dyn FnOnce(&mut State) + Send>>,
|
|
||||||
assert: impl FnOnce(&mut State) + Send + 'static,
|
|
||||||
) {
|
|
||||||
sender.send(Box::new(assert)).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sleep_secs(secs: u64) {
|
|
||||||
std::thread::sleep(Duration::from_secs(secs));
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! run_lua {
|
macro_rules! run_lua {
|
||||||
{ |$ident:ident| $($body:tt)* } => {
|
{ |$ident:ident| $($body:tt)* } => {
|
||||||
run_lua(stringify!($ident), stringify!($($body)*));
|
run_lua(stringify!($ident), stringify!($($body)*));
|
||||||
|
@ -117,63 +99,6 @@ macro_rules! setup_lua {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_lua_api(
|
|
||||||
test: impl FnOnce(Sender<Box<dyn FnOnce(&mut State) + Send>>) + Send + UnwindSafe + 'static,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
let (mut state, mut event_loop) = setup_dummy(true, None)?;
|
|
||||||
|
|
||||||
let (sender, recv) = calloop::channel::channel::<Box<dyn FnOnce(&mut State) + Send>>();
|
|
||||||
|
|
||||||
event_loop
|
|
||||||
.handle()
|
|
||||||
.insert_source(recv, |event, _, state| match event {
|
|
||||||
Event::Msg(f) => f(state),
|
|
||||||
Event::Closed => (),
|
|
||||||
})
|
|
||||||
.map_err(|_| anyhow::anyhow!("failed to insert source"))?;
|
|
||||||
|
|
||||||
let tempdir = tempfile::tempdir()?;
|
|
||||||
|
|
||||||
state.start_grpc_server(tempdir.path())?;
|
|
||||||
|
|
||||||
let loop_signal = event_loop.get_signal();
|
|
||||||
|
|
||||||
let join_handle = std::thread::spawn(move || {
|
|
||||||
let res = std::panic::catch_unwind(|| {
|
|
||||||
test(sender);
|
|
||||||
});
|
|
||||||
loop_signal.stop();
|
|
||||||
if let Err(err) = res {
|
|
||||||
std::panic::resume_unwind(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
event_loop.run(None, &mut state, |state| {
|
|
||||||
state.fixup_z_layering();
|
|
||||||
state.space.refresh();
|
|
||||||
state.popup_manager.cleanup();
|
|
||||||
|
|
||||||
state
|
|
||||||
.display_handle
|
|
||||||
.flush_clients()
|
|
||||||
.expect("failed to flush client buffers");
|
|
||||||
|
|
||||||
// TODO: couple these or something, this is really error-prone
|
|
||||||
assert_eq!(
|
|
||||||
state.windows.len(),
|
|
||||||
state.z_index_stack.len(),
|
|
||||||
"Length of `windows` and `z_index_stack` are different. \
|
|
||||||
If you see this, report it to the developer."
|
|
||||||
);
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if let Err(err) = join_handle.join() {
|
|
||||||
panic!("{err:?}");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
mod coverage {
|
mod coverage {
|
||||||
use pinnacle::{
|
use pinnacle::{
|
||||||
tag::TagId,
|
tag::TagId,
|
||||||
|
@ -188,12 +113,13 @@ mod coverage {
|
||||||
// Process
|
// Process
|
||||||
|
|
||||||
mod process {
|
mod process {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
#[self::test]
|
#[self::test]
|
||||||
async fn spawn() -> anyhow::Result<()> {
|
async fn spawn() -> anyhow::Result<()> {
|
||||||
test_lua_api(|sender| {
|
test_api(|sender| {
|
||||||
run_lua! { |Pinnacle|
|
run_lua! { |Pinnacle|
|
||||||
Pinnacle.process.spawn("foot")
|
Pinnacle.process.spawn("foot")
|
||||||
}
|
}
|
||||||
|
@ -210,7 +136,7 @@ mod coverage {
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
#[self::test]
|
#[self::test]
|
||||||
async fn set_env() -> anyhow::Result<()> {
|
async fn set_env() -> anyhow::Result<()> {
|
||||||
test_lua_api(|sender| {
|
test_api(|sender| {
|
||||||
run_lua! { |Pinnacle|
|
run_lua! { |Pinnacle|
|
||||||
Pinnacle.process.set_env("PROCESS_SET_ENV", "env value")
|
Pinnacle.process.set_env("PROCESS_SET_ENV", "env value")
|
||||||
}
|
}
|
||||||
|
@ -235,7 +161,7 @@ mod coverage {
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
#[self::test]
|
#[self::test]
|
||||||
async fn get_all() -> anyhow::Result<()> {
|
async fn get_all() -> anyhow::Result<()> {
|
||||||
test_lua_api(|_sender| {
|
test_api(|_sender| {
|
||||||
run_lua! { |Pinnacle|
|
run_lua! { |Pinnacle|
|
||||||
assert(#Pinnacle.window.get_all() == 0)
|
assert(#Pinnacle.window.get_all() == 0)
|
||||||
|
|
||||||
|
@ -255,7 +181,7 @@ mod coverage {
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
#[self::test]
|
#[self::test]
|
||||||
async fn get_focused() -> anyhow::Result<()> {
|
async fn get_focused() -> anyhow::Result<()> {
|
||||||
test_lua_api(|_sender| {
|
test_api(|_sender| {
|
||||||
run_lua! { |Pinnacle|
|
run_lua! { |Pinnacle|
|
||||||
assert(not Pinnacle.window.get_focused())
|
assert(not Pinnacle.window.get_focused())
|
||||||
|
|
||||||
|
@ -274,7 +200,7 @@ mod coverage {
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
#[self::test]
|
#[self::test]
|
||||||
async fn add_window_rule() -> anyhow::Result<()> {
|
async fn add_window_rule() -> anyhow::Result<()> {
|
||||||
test_lua_api(|sender| {
|
test_api(|sender| {
|
||||||
run_lua! { |Pinnacle|
|
run_lua! { |Pinnacle|
|
||||||
Pinnacle.tag.add(Pinnacle.output.get_focused(), "Tag Name")
|
Pinnacle.tag.add(Pinnacle.output.get_focused(), "Tag Name")
|
||||||
Pinnacle.window.add_window_rule({
|
Pinnacle.window.add_window_rule({
|
||||||
|
@ -356,7 +282,7 @@ mod coverage {
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
#[self::test]
|
#[self::test]
|
||||||
async fn close() -> anyhow::Result<()> {
|
async fn close() -> anyhow::Result<()> {
|
||||||
test_lua_api(|sender| {
|
test_api(|sender| {
|
||||||
run_lua! { |Pinnacle|
|
run_lua! { |Pinnacle|
|
||||||
Pinnacle.process.spawn("foot")
|
Pinnacle.process.spawn("foot")
|
||||||
}
|
}
|
||||||
|
@ -382,7 +308,7 @@ mod coverage {
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
#[self::test]
|
#[self::test]
|
||||||
async fn move_to_tag() -> anyhow::Result<()> {
|
async fn move_to_tag() -> anyhow::Result<()> {
|
||||||
test_lua_api(|sender| {
|
test_api(|sender| {
|
||||||
run_lua! { |Pinnacle|
|
run_lua! { |Pinnacle|
|
||||||
local tags = Pinnacle.tag.add(Pinnacle.output.get_focused(), "1", "2", "3")
|
local tags = Pinnacle.tag.add(Pinnacle.output.get_focused(), "1", "2", "3")
|
||||||
tags[1]:set_active(true)
|
tags[1]:set_active(true)
|
||||||
|
@ -452,7 +378,7 @@ mod coverage {
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
#[self::test]
|
#[self::test]
|
||||||
async fn props() -> anyhow::Result<()> {
|
async fn props() -> anyhow::Result<()> {
|
||||||
test_lua_api(|_sender| {
|
test_api(|_sender| {
|
||||||
run_lua! { |Pinnacle|
|
run_lua! { |Pinnacle|
|
||||||
Pinnacle.output.connect_for_all(function(op)
|
Pinnacle.output.connect_for_all(function(op)
|
||||||
local tags = Pinnacle.tag.add(op, "First", "Mungus", "Potato")
|
local tags = Pinnacle.tag.add(op, "First", "Mungus", "Potato")
|
||||||
|
@ -506,7 +432,7 @@ mod coverage {
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
#[self::test]
|
#[self::test]
|
||||||
async fn setup() -> anyhow::Result<()> {
|
async fn setup() -> anyhow::Result<()> {
|
||||||
test_lua_api(|sender| {
|
test_api(|sender| {
|
||||||
setup_lua! { |Pinnacle|
|
setup_lua! { |Pinnacle|
|
||||||
Pinnacle.output.setup({
|
Pinnacle.output.setup({
|
||||||
{
|
{
|
||||||
|
@ -626,7 +552,7 @@ mod coverage {
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
#[test]
|
#[test]
|
||||||
async fn window_count_with_tag_is_correct() -> anyhow::Result<()> {
|
async fn window_count_with_tag_is_correct() -> anyhow::Result<()> {
|
||||||
test_lua_api(|sender| {
|
test_api(|sender| {
|
||||||
run_lua! { |Pinnacle|
|
run_lua! { |Pinnacle|
|
||||||
Pinnacle.tag.add(Pinnacle.output.get_focused(), "1")
|
Pinnacle.tag.add(Pinnacle.output.get_focused(), "1")
|
||||||
Pinnacle.process.spawn("foot")
|
Pinnacle.process.spawn("foot")
|
||||||
|
@ -651,7 +577,7 @@ async fn window_count_with_tag_is_correct() -> anyhow::Result<()> {
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
#[test]
|
#[test]
|
||||||
async fn window_count_without_tag_is_correct() -> anyhow::Result<()> {
|
async fn window_count_without_tag_is_correct() -> anyhow::Result<()> {
|
||||||
test_lua_api(|sender| {
|
test_api(|sender| {
|
||||||
run_lua! { |Pinnacle|
|
run_lua! { |Pinnacle|
|
||||||
Pinnacle.process.spawn("foot")
|
Pinnacle.process.spawn("foot")
|
||||||
}
|
}
|
||||||
|
@ -665,7 +591,7 @@ async fn window_count_without_tag_is_correct() -> anyhow::Result<()> {
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
#[test]
|
#[test]
|
||||||
async fn spawned_window_on_active_tag_has_keyboard_focus() -> anyhow::Result<()> {
|
async fn spawned_window_on_active_tag_has_keyboard_focus() -> anyhow::Result<()> {
|
||||||
test_lua_api(|sender| {
|
test_api(|sender| {
|
||||||
run_lua! { |Pinnacle|
|
run_lua! { |Pinnacle|
|
||||||
Pinnacle.tag.add(Pinnacle.output.get_focused(), "1")[1]:set_active(true)
|
Pinnacle.tag.add(Pinnacle.output.get_focused(), "1")[1]:set_active(true)
|
||||||
Pinnacle.process.spawn("foot")
|
Pinnacle.process.spawn("foot")
|
||||||
|
@ -688,7 +614,7 @@ async fn spawned_window_on_active_tag_has_keyboard_focus() -> anyhow::Result<()>
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
#[test]
|
#[test]
|
||||||
async fn spawned_window_on_inactive_tag_does_not_have_keyboard_focus() -> anyhow::Result<()> {
|
async fn spawned_window_on_inactive_tag_does_not_have_keyboard_focus() -> anyhow::Result<()> {
|
||||||
test_lua_api(|sender| {
|
test_api(|sender| {
|
||||||
run_lua! { |Pinnacle|
|
run_lua! { |Pinnacle|
|
||||||
Pinnacle.tag.add(Pinnacle.output.get_focused(), "1")
|
Pinnacle.tag.add(Pinnacle.output.get_focused(), "1")
|
||||||
Pinnacle.process.spawn("foot")
|
Pinnacle.process.spawn("foot")
|
||||||
|
@ -705,7 +631,7 @@ async fn spawned_window_on_inactive_tag_does_not_have_keyboard_focus() -> anyhow
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
#[test]
|
#[test]
|
||||||
async fn spawned_window_has_correct_tags() -> anyhow::Result<()> {
|
async fn spawned_window_has_correct_tags() -> anyhow::Result<()> {
|
||||||
test_lua_api(|sender| {
|
test_api(|sender| {
|
||||||
run_lua! { |Pinnacle|
|
run_lua! { |Pinnacle|
|
||||||
Pinnacle.tag.add(Pinnacle.output.get_focused(), "1", "2", "3")
|
Pinnacle.tag.add(Pinnacle.output.get_focused(), "1", "2", "3")
|
||||||
Pinnacle.process.spawn("foot")
|
Pinnacle.process.spawn("foot")
|
||||||
|
|
100
tests/rust_api.rs
Normal file
100
tests/rust_api.rs
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
mod common;
|
||||||
|
|
||||||
|
use std::thread::JoinHandle;
|
||||||
|
|
||||||
|
use pinnacle_api::ApiModules;
|
||||||
|
use test_log::test;
|
||||||
|
|
||||||
|
use crate::common::{sleep_secs, test_api, with_state};
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn setup_rust_inner(run: impl FnOnce(ApiModules) + Send + 'static) {
|
||||||
|
let (api, recv) = pinnacle_api::connect().await.unwrap();
|
||||||
|
|
||||||
|
run(api);
|
||||||
|
|
||||||
|
pinnacle_api::listen(recv).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_rust(run: impl FnOnce(ApiModules) + Send + 'static) -> JoinHandle<()> {
|
||||||
|
std::thread::spawn(|| {
|
||||||
|
setup_rust_inner(run);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
mod output {
|
||||||
|
use pinnacle_api::output::{Alignment, OutputMatcher, OutputSetup};
|
||||||
|
use smithay::utils::Rectangle;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
#[self::test]
|
||||||
|
async fn setup() -> anyhow::Result<()> {
|
||||||
|
test_api(|sender| {
|
||||||
|
setup_rust(|api| {
|
||||||
|
api.output
|
||||||
|
.setup([OutputSetup::new_with_matcher(|_| true).with_tags(["1", "2", "3"])]);
|
||||||
|
});
|
||||||
|
|
||||||
|
sleep_secs(1);
|
||||||
|
|
||||||
|
with_state(&sender, |state| {
|
||||||
|
state.new_output("First", (300, 200).into());
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
#[self::test]
|
||||||
|
async fn setup_with_cyclic_relative_tos_work() -> anyhow::Result<()> {
|
||||||
|
test_api(|sender| {
|
||||||
|
setup_rust(|api| {
|
||||||
|
api.output.setup([
|
||||||
|
OutputSetup::new("Pinnacle Window"),
|
||||||
|
OutputSetup::new("First").with_relative_loc(
|
||||||
|
OutputMatcher::Name("Second".into()),
|
||||||
|
Alignment::RightAlignTop,
|
||||||
|
),
|
||||||
|
OutputSetup::new("Second").with_relative_loc(
|
||||||
|
OutputMatcher::Name("First".into()),
|
||||||
|
Alignment::LeftAlignTop,
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
sleep_secs(1);
|
||||||
|
|
||||||
|
with_state(&sender, |state| {
|
||||||
|
state.new_output("First", (300, 200).into());
|
||||||
|
});
|
||||||
|
|
||||||
|
sleep_secs(1);
|
||||||
|
|
||||||
|
with_state(&sender, |state| {
|
||||||
|
let original_op = state
|
||||||
|
.space
|
||||||
|
.outputs()
|
||||||
|
.find(|op| op.name() == "Pinnacle Window")
|
||||||
|
.unwrap();
|
||||||
|
let first_op = state
|
||||||
|
.space
|
||||||
|
.outputs()
|
||||||
|
.find(|op| op.name() == "First")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let original_geo = state.space.output_geometry(original_op).unwrap();
|
||||||
|
let first_geo = state.space.output_geometry(first_op).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
original_geo,
|
||||||
|
Rectangle::from_loc_and_size((0, 0), (1920, 1080))
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
first_geo,
|
||||||
|
Rectangle::from_loc_and_size((1920, 0), (300, 200))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue