From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 067D2C00144 for ; Wed, 27 Jul 2022 02:59:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S240181AbiG0C67 (ORCPT ); Tue, 26 Jul 2022 22:58:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35018 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S240168AbiG0C66 (ORCPT ); Tue, 26 Jul 2022 22:58:58 -0400 Received: from mail-pl1-x62c.google.com (mail-pl1-x62c.google.com [IPv6:2607:f8b0:4864:20::62c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0AC0E37F83 for ; Tue, 26 Jul 2022 19:58:55 -0700 (PDT) Received: by mail-pl1-x62c.google.com with SMTP id w7so14989924ply.12 for ; Tue, 26 Jul 2022 19:58:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to; bh=2d4L6RErDyCEScfvRmJ+4W2SZB0+zt7F+d3bODSzgzk=; b=XpT80C13g+//N2tGq/Jg4ADiFrZagoC3zzDUbcGXOTsYoNqNeo9jQQCt6pZgV89a68 z0rhnZPU7H7gnsTcyrs/1f6tiTIrDzq2853QBpzzL/7tu9cXFqMvCunJYCEYGV1LXKh8 P92M6uOSGBYKjXTXF3ESIXKwMq/XEPOyfNDVgxVyymPJQdDXXvRQX5O+IRE+cjB+RkUs Z/PD2a7zK68SjVzvbKF5QseP1iXAFYST/Mt57XRbnyIrcT9H7O7fPtfJznGZfEqekGEN 3NdzjuU+zhpGb1OZgvqCLNbqVzX6O1qJMMZH6A6izEG24Sow2fuSayejxlLhImr+k2ob V19A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=2d4L6RErDyCEScfvRmJ+4W2SZB0+zt7F+d3bODSzgzk=; b=4wKKHo1wjtOsXpy4XM+KwK61wi/b+901YvzafYXZov/SBYr9SFoxH/jUJT6ouUp1uE pbUVZC+PcfMfI31hLxRjzjstb+xj3v+KyI7ks47uckN1IwupP0FrS8l2UWkGYaRniO0C j3Qsm0CnjK29LtQ1YXsxLnGQd+vDhdpduZUEHIbz/2ESmwzPWYj2k9G27kslFdJbiRMc Mta1ngdUFijORvQ9FvyP7Q8/+Re9xl0hzNy47xyyUaCWnELU6rD54LTLwxfKTG3jXO9q SyMq1tcwElwTEvgwr67qWL7shScwO/BCUivFN00Hj2bjXXKXc0t32QHHuil5Rylz+yqj Stcg== X-Gm-Message-State: AJIora8whvsXpL9DlBrM/aR5kGiI9rhhrq3vs3e6FXglZwddIdp31phg vBgu4fo608p7HhsKRwtOWTmdbe7qN/8= X-Google-Smtp-Source: AGRyM1s/Q1pZCH9oiKcUPS8xx+QL5r5GjDEqgnRuyu856ysOeNz9WiIX80vWRibxmMVapxsfASF0qA== X-Received: by 2002:a17:90b:4c51:b0:1f2:46b2:7c28 with SMTP id np17-20020a17090b4c5100b001f246b27c28mr2159394pjb.231.1658890733886; Tue, 26 Jul 2022 19:58:53 -0700 (PDT) Received: from sol (110-174-58-111.static.tpgi.com.au. [110.174.58.111]) by smtp.gmail.com with ESMTPSA id s20-20020a170902a51400b001620960f1dfsm12203479plq.198.2022.07.26.19.58.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 Jul 2022 19:58:53 -0700 (PDT) Date: Wed, 27 Jul 2022 10:58:47 +0800 From: Kent Gibson To: Viresh Kumar Cc: Linus Walleij , Bartosz Golaszewski , Vincent Guittot , linux-gpio@vger.kernel.org, Miguel Ojeda , Wedson Almeida Filho , Alex =?iso-8859-1?Q?Benn=E9e?= , stratos-dev@op-lists.linaro.org, Gerard Ryan Subject: Re: [PATCH V4 7/8] libgpiod: Add rust tests Message-ID: <20220727025847.GG88787@sol> References: <78b3ee21dec2a66003c2eae2800e9699a8ecd180.1657279685.git.viresh.kumar@linaro.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <78b3ee21dec2a66003c2eae2800e9699a8ecd180.1657279685.git.viresh.kumar@linaro.org> Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org On Fri, Jul 08, 2022 at 05:05:00PM +0530, Viresh Kumar wrote: > Add tests for the rust bindings, quite similar to the ones in cxx > bindings. > > This is how "cargo test" prints results: > Don't include the test results in the commit message. Those are more of a release artifact than a commit artifact. It is assumed the tests pass for you or you wouldn't be submitting them. > Running tests/chip.rs (target/debug/deps/chip-b19008e6b9a10d2f) > > running 6 tests > test chip::create::nonexistent_file_failure ... ok > test chip::create::no_dev_file_failure ... ok > test chip::create::non_gpio_char_dev_file_failure ... ok > test chip::create::existing ... ok > test chip::configure::line_lookup ... ok > test chip::configure::verify ... ok > > test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.14s > > Running tests/edge_event.rs (target/debug/deps/edge_event-5897a36c91efe0d4) > > running 11 tests > test edge_event::buffer_settings::default_capacity ... ok > test edge_event::buffer_settings::user_defined_capacity ... ok > test edge_event::buffer_settings::max_capacity ... ok > test edge_event::failure::dir_out_edge_failure ... ok > test edge_event::failure::wait_timeout ... ok > test edge_event::verify::both_edges ... ok > test edge_event::verify::multiple_events ... ok > test edge_event::verify::edge_sequence ... ok > test edge_event::verify::falling_edge ... ok > test edge_event::verify::over_capacity ... ok > test edge_event::verify::rising_edge ... ok > > test result: ok. 11 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.98s > > Running tests/info_event.rs (target/debug/deps/info_event-707c734e0820381c) > > running 3 tests > test info_event::watch::verify ... ok > test info_event::watch::failure ... ok > test info_event::watch::reconfigure ... ok > > test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.26s > > Running tests/line_config.rs (target/debug/deps/line_config-d376966750bf38a0) > > running 9 tests > test line_config::overrides::active_low ... ok > test line_config::overrides::bias ... ok > test line_config::default::verify ... ok > test line_config::overrides::debounce_period ... ok > test line_config::overrides::direction ... ok > test line_config::overrides::drive ... ok > test line_config::overrides::edge_detection ... ok > test line_config::overrides::event_clock ... ok > test line_config::overrides::output_value ... ok > > test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s > > Running tests/line_info.rs (target/debug/deps/line_info-5069196cfaa74ab7) > > running 2 tests > [40570.967204] gpio-1992 (hog): hogged as output/high > [40570.974774] gpio-1956 (hog4): hogged as output/low > [40570.975314] gpio-1955 (hog3): hogged as output/high > test line_info::properties::verify ... ok > test line_info::basic::verify ... ok > > test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.31s > > Running tests/line_request.rs (target/debug/deps/line_request-914b9fd8c84e2c4b) > > running 7 tests > test line_request::invalid_arguments::no_offsets ... ok > test line_request::verify::read_values ... ok > test line_request::verify::set_bias ... ok > test line_request::verify::reconfigure_output_values ... ok > test line_request::verify::empty_consumer ... ok > test line_request::verify::set_output_values ... ok > test line_request::verify::custom_consumer ... ok > > test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.48s > > Running tests/request_config.rs (target/debug/deps/request_config-99e366517cc0feda) > > running 2 tests > test request_config::verify::default ... ok > test request_config::verify::initialized ... ok > > test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s > > Doc-tests libgpiod > > running 0 tests > > test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s > > Signed-off-by: Viresh Kumar > --- > bindings/rust/Cargo.toml | 3 + > bindings/rust/src/line_request.rs | 1 + > bindings/rust/tests/chip.rs | 96 +++++++ > bindings/rust/tests/common/config.rs | 117 ++++++++ > bindings/rust/tests/common/mod.rs | 16 ++ > bindings/rust/tests/common/sim.rs | 306 ++++++++++++++++++++ > bindings/rust/tests/edge_event.rs | 389 ++++++++++++++++++++++++++ > bindings/rust/tests/info_event.rs | 126 +++++++++ > bindings/rust/tests/line_config.rs | 187 +++++++++++++ > bindings/rust/tests/line_info.rs | 90 ++++++ > bindings/rust/tests/line_request.rs | 234 ++++++++++++++++ > bindings/rust/tests/request_config.rs | 42 +++ > 12 files changed, 1607 insertions(+) > create mode 100644 bindings/rust/tests/chip.rs > create mode 100644 bindings/rust/tests/common/config.rs > create mode 100644 bindings/rust/tests/common/mod.rs > create mode 100644 bindings/rust/tests/common/sim.rs > create mode 100644 bindings/rust/tests/edge_event.rs > create mode 100644 bindings/rust/tests/info_event.rs > create mode 100644 bindings/rust/tests/line_config.rs > create mode 100644 bindings/rust/tests/line_info.rs > create mode 100644 bindings/rust/tests/line_request.rs > create mode 100644 bindings/rust/tests/request_config.rs > > diff --git a/bindings/rust/Cargo.toml b/bindings/rust/Cargo.toml > index d5d81486fa2f..e2d6d5bb91b6 100644 > --- a/bindings/rust/Cargo.toml > +++ b/bindings/rust/Cargo.toml > @@ -10,3 +10,6 @@ libc = ">=0.2.39" > libgpiod-sys = { path = "libgpiod-sys" } > thiserror = "1.0" > vmm-sys-util = "=0.9.0" > + > +[dev-dependencies] > +libgpiod-sys = { path = "libgpiod-sys", features = ["gpiosim"] } > diff --git a/bindings/rust/src/line_request.rs b/bindings/rust/src/line_request.rs > index bb338e72671d..c1dbbb397e73 100644 > --- a/bindings/rust/src/line_request.rs > +++ b/bindings/rust/src/line_request.rs > @@ -15,6 +15,7 @@ use super::{bindings, ChipInternal, EdgeEventBuffer, Error, LineConfig, RequestC > /// Line request operations > /// > /// Allows interaction with a set of requested lines. > +#[derive(Debug)] > pub struct LineRequest { > request: *mut bindings::gpiod_line_request, > } Overlooked in patch 6? Squash that into patch 4 as well. > diff --git a/bindings/rust/tests/chip.rs b/bindings/rust/tests/chip.rs > new file mode 100644 > index 000000000000..4e64e9c7e291 > --- /dev/null > +++ b/bindings/rust/tests/chip.rs > @@ -0,0 +1,96 @@ > +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause > +// > +// Copyright 2022 Linaro Ltd. All Rights Reserved. > +// Viresh Kumar > + > +mod common; > + > +mod chip { > + use libc::{ENODEV, ENOENT, ENOTTY}; > + > + use vmm_sys_util::errno::Error as IoError; > + > + use crate::common::*; > + use libgpiod::{Chip, Error as ChipError}; > + > + mod create { If it is testing the open method then call it "open"? > + use super::*; > + > + #[test] > + fn nonexistent_file_failure() { > + assert_eq!( > + Chip::open("/dev/nonexistent").unwrap_err(), > + ChipError::OperationFailed("Gpio Chip open", IoError::new(ENOENT)) > + ); > + } The "_failure" suffix doesn't add anything, so remove it. > + > + #[test] > + fn no_dev_file_failure() { > + assert_eq!( > + Chip::open("/tmp").unwrap_err(), > + ChipError::OperationFailed("Gpio Chip open", IoError::new(ENOTTY)) > + ); > + } > + > + #[test] > + fn non_gpio_char_dev_file_failure() { > + assert_eq!( > + Chip::open("/dev/null").unwrap_err(), > + ChipError::OperationFailed("Gpio Chip open", IoError::new(ENODEV)) > + ); > + } > + > + #[test] > + fn existing() { > + let sim = Sim::new(None, None, true).unwrap(); > + Chip::open(sim.dev_path()).unwrap(); Test names should indicate what the test covers. "existing" doesn't quite do that for me, though last I checked I passed. YMMV. Use an assert variant for explicit tests. Only use unwrap() for intermediate steps that are part of the fixture and are expected to pass unless something is very broken in the test setup. That makes it easier to distinguish the meat from the skeleton. > + } > + } > + > + mod configure { > + use super::*; > + const NGPIO: u64 = 16; > + const LABEL: &str = "foobar"; > + > + #[test] > + fn verify() { > + let sim = Sim::new(Some(NGPIO), Some(LABEL), true).unwrap(); > + let chip = Chip::open(sim.dev_path()).unwrap(); > + > + assert_eq!(chip.get_label().unwrap(), LABEL); > + assert_eq!(chip.get_name().unwrap(), sim.chip_name()); > + assert_eq!(chip.get_path().unwrap(), sim.dev_path()); > + assert_eq!(chip.get_num_lines(), NGPIO as u32); > + chip.get_fd().unwrap(); > + } > + A test for a basic open on an existing chip and a smoke test of some chip methods is called "verify", so chip::configure::verify? > + #[test] > + fn line_lookup() { > + let sim = Sim::new(Some(NGPIO), None, false).unwrap(); > + sim.set_line_name(0, "zero").unwrap(); > + sim.set_line_name(2, "two").unwrap(); > + sim.set_line_name(3, "three").unwrap(); > + sim.set_line_name(5, "five").unwrap(); > + sim.set_line_name(10, "ten").unwrap(); > + sim.set_line_name(11, "ten").unwrap(); > + sim.enable().unwrap(); > + > + let chip = Chip::open(sim.dev_path()).unwrap(); > + > + // Success case > + assert_eq!(chip.find_line("zero").unwrap(), 0); > + assert_eq!(chip.find_line("two").unwrap(), 2); > + assert_eq!(chip.find_line("three").unwrap(), 3); > + assert_eq!(chip.find_line("five").unwrap(), 5); > + > + // Success with duplicate names, should return first entry > + assert_eq!(chip.find_line("ten").unwrap(), 10); > + > + // Failure > + assert_eq!( > + chip.find_line("nonexistent").unwrap_err(), > + ChipError::OperationFailed("Gpio Chip find-line", IoError::new(ENOENT)) > + ); > + } If it is testing find_line() then why not call it find_line? > + } > +} > diff --git a/bindings/rust/tests/common/config.rs b/bindings/rust/tests/common/config.rs > new file mode 100644 > index 000000000000..3abd9a8c4c8b > --- /dev/null > +++ b/bindings/rust/tests/common/config.rs > @@ -0,0 +1,117 @@ > +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause > +// > +// Copyright 2022 Linaro Ltd. All Rights Reserved. > +// Viresh Kumar > + > +use std::sync::Arc; > + > +use crate::common::*; > + > +use libgpiod::{Bias, Chip, Direction, Edge, LineConfig, LineRequest, RequestConfig, Result}; > + > +//#[derive(Debug)] Uncomment or remove. > +pub(crate) struct TestConfig { > + sim: Arc, > + chip: Option, > + request: Option, > + rconfig: RequestConfig, > + lconfig: LineConfig, > +} > + > +impl TestConfig { > + pub(crate) fn new(ngpio: u64) -> Result { > + Ok(Self { > + sim: Arc::new(Sim::new(Some(ngpio), None, true)?), > + chip: None, > + request: None, > + rconfig: RequestConfig::new().unwrap(), > + lconfig: LineConfig::new().unwrap(), > + }) > + } > + > + pub(crate) fn set_pull(&self, offsets: &[u32], pulls: &[u32]) { > + for i in 0..pulls.len() { > + self.sim.set_pull(offsets[i], pulls[i] as i32).unwrap(); > + } > + } > + > + pub(crate) fn rconfig_consumer(&self, offsets: Option<&[u32]>, consumer: Option<&str>) { > + if let Some(offsets) = offsets { > + self.rconfig.set_offsets(offsets); > + } > + > + if let Some(consumer) = consumer { > + self.rconfig.set_consumer(consumer); > + } > + } > + > + pub(crate) fn rconfig(&self, offsets: Option<&[u32]>) { > + self.rconfig_consumer(offsets, None); > + } Almost always called with Some(&offsets), and calling it with None is a NOP. Where called with Some just call rconfig.set_offsets(). Remove instances of calling with None. > + > + pub(crate) fn lconfig( > + &mut self, > + dir: Option, > + val: Option, > + val_override: Option<(u32, u32)>, > + edge: Option, > + bias: Option, > + ) { > + if let Some(bias) = bias { > + self.lconfig.set_bias_default(bias); > + } > + > + if let Some(edge) = edge { > + self.lconfig.set_edge_detection_default(edge); > + } > + > + if let Some(dir) = dir { > + self.lconfig.set_direction_default(dir); > + } > + > + if let Some(val) = val { > + self.lconfig.set_output_value_default(val); > + } > + > + if let Some((offset, val)) = val_override { > + self.lconfig.set_output_value_override(val, offset); > + } > + } > + > + pub(crate) fn lconfig_raw(&mut self) { > + self.lconfig(None, None, None, None, None); > + } > + > + pub(crate) fn lconfig_edge(&mut self, edge: Option) { > + self.lconfig(None, None, None, edge, None); > + } > + > + pub(crate) fn request_lines(&mut self) -> Result<()> { > + let chip = Chip::open(self.sim.dev_path())?; > + > + self.request = Some(chip.request_lines(&self.rconfig, &self.lconfig)?); > + self.chip = Some(chip); > + > + Ok(()) > + } > + > + pub(crate) fn sim(&self) -> Arc { > + self.sim.clone() > + } > + > + pub(crate) fn chip(&self) -> &Chip { > + &self.chip.as_ref().unwrap() > + } > + > + pub(crate) fn request(&self) -> &LineRequest { > + &self.request.as_ref().unwrap() > + } > +} > + > +impl Drop for TestConfig { > + fn drop(&mut self) { > + // Explicit freeing is important to make sure "request" get freed > + // before "sim" and "chip". > + self.request = None; > + } > +} > diff --git a/bindings/rust/tests/common/mod.rs b/bindings/rust/tests/common/mod.rs > new file mode 100644 > index 000000000000..2dc37986396b > --- /dev/null > +++ b/bindings/rust/tests/common/mod.rs > @@ -0,0 +1,16 @@ > +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause > +// > +// Copyright 2022 Linaro Ltd. All Rights Reserved. > +// Viresh Kumar > + > +#[allow(dead_code)] > +mod sim; > + > +#[allow(unused_imports)] > +pub(crate) use sim::*; This allow seems unnecessary. > + > +#[allow(dead_code)] > +mod config; > + > +#[allow(unused_imports)] > +pub(crate) use config::*; The dead_code allows make me think there is a problem with the way the common test code is structured or there is actual dead code in there. common/sim.rs should be part of a gpiosim crate?? > diff --git a/bindings/rust/tests/common/sim.rs b/bindings/rust/tests/common/sim.rs > new file mode 100644 > index 000000000000..cd5ec66c3da5 > --- /dev/null > +++ b/bindings/rust/tests/common/sim.rs > @@ -0,0 +1,306 @@ > +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause > +// > +// Copyright 2022 Linaro Ltd. All Rights Reserved. > +// Viresh Kumar > + > +use std::os::raw::c_char; > +use std::{slice, str}; > + > +use vmm_sys_util::errno::Error as IoError; > + > +use libgpiod::{Error, Result}; > +use libgpiod_sys as bindings; > + > +/// Sim Ctx > +#[derive(Debug)] > +struct SimCtx { > + ctx: *mut bindings::gpiosim_ctx, > +} > + > +unsafe impl Send for SimCtx {} > +unsafe impl Sync for SimCtx {} > + > +impl SimCtx { > + fn new() -> Result { > + let ctx = unsafe { bindings::gpiosim_ctx_new() }; > + if ctx.is_null() { > + return Err(Error::OperationFailed("gpio-sim ctx new", IoError::last())); > + } > + > + Ok(Self { ctx }) > + } > + > + fn ctx(&self) -> *mut bindings::gpiosim_ctx { > + self.ctx > + } > +} > + > +impl Drop for SimCtx { > + fn drop(&mut self) { > + unsafe { bindings::gpiosim_ctx_unref(self.ctx) } > + } > +} > + > +/// Sim Dev > +#[derive(Debug)] > +struct SimDev { > + dev: *mut bindings::gpiosim_dev, > +} > + > +unsafe impl Send for SimDev {} > +unsafe impl Sync for SimDev {} > + > +impl SimDev { > + fn new(ctx: &SimCtx) -> Result { > + let dev = unsafe { bindings::gpiosim_dev_new(ctx.ctx()) }; > + if dev.is_null() { > + return Err(Error::OperationFailed("gpio-sim dev new", IoError::last())); > + } > + > + Ok(Self { dev }) > + } > + > + fn dev(&self) -> *mut bindings::gpiosim_dev { > + self.dev > + } > + > + fn enable(&self) -> Result<()> { > + let ret = unsafe { bindings::gpiosim_dev_enable(self.dev) }; > + > + if ret == -1 { > + Err(Error::OperationFailed( > + "gpio-sim dev-enable", > + IoError::last(), > + )) > + } else { > + Ok(()) > + } > + } > + > + fn disable(&self) -> Result<()> { > + let ret = unsafe { bindings::gpiosim_dev_disable(self.dev) }; > + > + if ret == -1 { > + Err(Error::OperationFailed( > + "gpio-sim dev-disable", > + IoError::last(), > + )) > + } else { > + Ok(()) > + } > + } > +} > + > +impl Drop for SimDev { > + fn drop(&mut self) { > + unsafe { bindings::gpiosim_dev_unref(self.dev) } > + } > +} > + > +/// Sim Bank > +#[derive(Debug)] > +struct SimBank { > + bank: *mut bindings::gpiosim_bank, > +} > + > +unsafe impl Send for SimBank {} > +unsafe impl Sync for SimBank {} > + > +impl SimBank { > + fn new(dev: &SimDev) -> Result { > + let bank = unsafe { bindings::gpiosim_bank_new(dev.dev()) }; > + if bank.is_null() { > + return Err(Error::OperationFailed("gpio-sim Bank new", IoError::last())); > + } > + > + Ok(Self { bank }) > + } > + > + fn chip_name(&self) -> Result<&str> { > + // SAFETY: The string returned by gpiosim is guaranteed to live as long > + // as the `struct SimBank`. > + let name = unsafe { bindings::gpiosim_bank_get_chip_name(self.bank) }; > + > + // SAFETY: The string is guaranteed to be valid here. > + str::from_utf8(unsafe { > + slice::from_raw_parts(name as *const u8, bindings::strlen(name) as usize) > + }) > + .map_err(Error::InvalidString) > + } > + > + fn dev_path(&self) -> Result<&str> { > + // SAFETY: The string returned by gpiosim is guaranteed to live as long > + // as the `struct SimBank`. > + let path = unsafe { bindings::gpiosim_bank_get_dev_path(self.bank) }; > + > + // SAFETY: The string is guaranteed to be valid here. > + str::from_utf8(unsafe { > + slice::from_raw_parts(path as *const u8, bindings::strlen(path) as usize) > + }) > + .map_err(Error::InvalidString) > + } > + > + fn val(&self, offset: u32) -> Result { > + let ret = unsafe { bindings::gpiosim_bank_get_value(self.bank, offset) }; > + > + if ret == -1 { > + Err(Error::OperationFailed( > + "gpio-sim get-value", > + IoError::last(), > + )) > + } else { > + Ok(ret as u32) > + } > + } > + > + fn set_label(&self, label: &str) -> Result<()> { > + // Null-terminate the string > + let label = label.to_owned() + "\0"; > + > + let ret = > + unsafe { bindings::gpiosim_bank_set_label(self.bank, label.as_ptr() as *const c_char) }; > + > + if ret == -1 { > + Err(Error::OperationFailed( > + "gpio-sim set-label", > + IoError::last(), > + )) > + } else { > + Ok(()) > + } > + } > + > + fn set_num_lines(&self, num: u64) -> Result<()> { > + let ret = unsafe { bindings::gpiosim_bank_set_num_lines(self.bank, num) }; > + if ret == -1 { > + Err(Error::OperationFailed( > + "gpio-sim set-num-lines", > + IoError::last(), > + )) > + } else { > + Ok(()) > + } > + } > + > + fn set_line_name(&self, offset: u32, name: &str) -> Result<()> { > + // Null-terminate the string > + let name = name.to_owned() + "\0"; > + > + let ret = unsafe { > + bindings::gpiosim_bank_set_line_name(self.bank, offset, name.as_ptr() as *const c_char) > + }; > + > + if ret == -1 { > + Err(Error::OperationFailed( > + "gpio-sim set-line-name", > + IoError::last(), > + )) > + } else { > + Ok(()) > + } > + } > + > + fn set_pull(&self, offset: u32, pull: i32) -> Result<()> { > + let ret = unsafe { bindings::gpiosim_bank_set_pull(self.bank, offset, pull) }; > + > + if ret == -1 { > + Err(Error::OperationFailed("gpio-sim set-pull", IoError::last())) > + } else { > + Ok(()) > + } > + } > + > + fn hog_line(&self, offset: u32, name: &str, dir: i32) -> Result<()> { > + // Null-terminate the string > + let name = name.to_owned() + "\0"; > + > + let ret = unsafe { > + bindings::gpiosim_bank_hog_line(self.bank, offset, name.as_ptr() as *const c_char, dir) > + }; > + > + if ret == -1 { > + Err(Error::OperationFailed("gpio-sim hog-line", IoError::last())) > + } else { > + Ok(()) > + } > + } > +} > + > +impl Drop for SimBank { > + fn drop(&mut self) { > + unsafe { bindings::gpiosim_bank_unref(self.bank) } > + } > +} > + > +/// GPIO SIM > +#[derive(Debug)] > +pub(crate) struct Sim { > + ctx: SimCtx, > + dev: SimDev, > + bank: SimBank, > +} > + > +unsafe impl Send for Sim {} > +unsafe impl Sync for Sim {} > + > +impl Sim { > + pub(crate) fn new(ngpio: Option, label: Option<&str>, enable: bool) -> Result { > + let ctx = SimCtx::new()?; > + let dev = SimDev::new(&ctx)?; > + let bank = SimBank::new(&dev)?; > + > + if let Some(ngpio) = ngpio { > + bank.set_num_lines(ngpio)?; > + } > + > + if let Some(label) = label { > + bank.set_label(label)?; > + } > + > + if enable { > + dev.enable()?; > + } > + > + Ok(Self { ctx, dev, bank }) > + } > + > + pub(crate) fn chip_name(&self) -> &str { > + self.bank.chip_name().unwrap() > + } > + > + pub fn dev_path(&self) -> &str { > + self.bank.dev_path().unwrap() > + } > + > + pub(crate) fn val(&self, offset: u32) -> Result { > + self.bank.val(offset) > + } > + > + pub(crate) fn set_label(&self, label: &str) -> Result<()> { > + self.bank.set_label(label) > + } > + > + pub(crate) fn set_num_lines(&self, num: u64) -> Result<()> { > + self.bank.set_num_lines(num) > + } > + > + pub(crate) fn set_line_name(&self, offset: u32, name: &str) -> Result<()> { > + self.bank.set_line_name(offset, name) > + } > + > + pub(crate) fn set_pull(&self, offset: u32, pull: i32) -> Result<()> { > + self.bank.set_pull(offset, pull) > + } > + > + pub(crate) fn hog_line(&self, offset: u32, name: &str, dir: i32) -> Result<()> { > + self.bank.hog_line(offset, name, dir) > + } > + > + pub(crate) fn enable(&self) -> Result<()> { > + self.dev.enable() > + } > + > + pub(crate) fn disable(&self) -> Result<()> { > + self.dev.disable() > + } > +} > diff --git a/bindings/rust/tests/edge_event.rs b/bindings/rust/tests/edge_event.rs > new file mode 100644 > index 000000000000..1b05b225aab7 > --- /dev/null > +++ b/bindings/rust/tests/edge_event.rs > @@ -0,0 +1,389 @@ > +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause > +// > +// Copyright 2022 Linaro Ltd. All Rights Reserved. > +// Viresh Kumar > + > +mod common; > + > +mod edge_event { > + use libc::EINVAL; > + use std::sync::Arc; > + use std::thread::{sleep, spawn}; > + use std::time::Duration; > + > + use vmm_sys_util::errno::Error as IoError; > + > + use crate::common::*; > + use libgpiod::{Direction, Edge, EdgeEventBuffer, Error as ChipError, LineEdgeEvent}; > + use libgpiod_sys::{GPIOSIM_PULL_DOWN, GPIOSIM_PULL_UP}; > + > + const NGPIO: u64 = 8; > + > + mod buffer_settings { > + use super::*; > + > + #[test] > + fn default_capacity() { > + assert_eq!(EdgeEventBuffer::new(0).unwrap().get_capacity(), 64); > + } > + > + #[test] > + fn user_defined_capacity() { > + assert_eq!(EdgeEventBuffer::new(123).unwrap().get_capacity(), 123); > + } > + > + #[test] > + fn max_capacity() { > + assert_eq!(EdgeEventBuffer::new(1024 * 2).unwrap().get_capacity(), 1024); > + } > + } > + > + mod failure { > + use super::*; > + Don't see the point of the failure/verify namespace level here. > + #[test] > + fn wait_timeout() { > + let mut config = TestConfig::new(NGPIO).unwrap(); > + config.rconfig(Some(&[0])); > + config.lconfig_edge(Some(Edge::Both)); > + config.request_lines().unwrap(); > + > + // No events available > + assert_eq!( > + config > + .request() > + .wait_edge_event(Duration::from_millis(100)) > + .unwrap_err(), > + ChipError::OperationTimedOut > + ); > + } Is a timeout really a "failure"? It is testing wait_edge_event(), which is a method of line_request, and so should be in the line_request test suite. > + > + #[test] > + fn dir_out_edge_failure() { > + let mut config = TestConfig::new(NGPIO).unwrap(); > + config.rconfig(Some(&[0])); > + config.lconfig(Some(Direction::Output), None, None, Some(Edge::Both), None); > + > + assert_eq!( > + config.request_lines().unwrap_err(), > + ChipError::OperationFailed("Gpio LineRequest request-lines", IoError::new(EINVAL)) > + ); > + } > + } > + This is testing a failure mode of request_lines(), not edge_events. Where is the edge_event here? > + mod verify { > + use super::*; > + > + // Helpers to generate events > + fn trigger_falling_and_rising_edge(sim: Arc, offset: u32) { > + spawn(move || { > + sleep(Duration::from_millis(30)); > + sim.set_pull(offset, GPIOSIM_PULL_UP as i32).unwrap(); > + > + sleep(Duration::from_millis(30)); > + sim.set_pull(offset, GPIOSIM_PULL_DOWN as i32).unwrap(); > + }); > + } > + > + fn trigger_rising_edge_events_on_two_offsets(sim: Arc, offset: [u32; 2]) { > + spawn(move || { > + sleep(Duration::from_millis(30)); > + sim.set_pull(offset[0], GPIOSIM_PULL_UP as i32).unwrap(); > + > + sleep(Duration::from_millis(30)); > + sim.set_pull(offset[1], GPIOSIM_PULL_UP as i32).unwrap(); > + }); > + } > + > + fn trigger_multiple_events(sim: Arc, offset: u32) { > + sim.set_pull(offset, GPIOSIM_PULL_UP as i32).unwrap(); > + sleep(Duration::from_millis(10)); > + > + sim.set_pull(offset, GPIOSIM_PULL_DOWN as i32).unwrap(); > + sleep(Duration::from_millis(10)); > + > + sim.set_pull(offset, GPIOSIM_PULL_UP as i32).unwrap(); > + sleep(Duration::from_millis(10)); > + } > + > + #[test] > + fn both_edges() { > + const GPIO: u32 = 2; > + let buf = EdgeEventBuffer::new(0).unwrap(); > + let mut config = TestConfig::new(NGPIO).unwrap(); > + config.rconfig(Some(&[GPIO])); > + config.lconfig_edge(Some(Edge::Both)); > + config.request_lines().unwrap(); > + > + // Generate events > + trigger_falling_and_rising_edge(config.sim(), GPIO); > + > + // Rising event > + config > + .request() > + .wait_edge_event(Duration::from_secs(1)) > + .unwrap(); > + > + assert_eq!( > + config > + .request() > + .read_edge_event(&buf, buf.get_capacity()) > + .unwrap(), > + 1 > + ); > + assert_eq!(buf.get_num_events(), 1); > + > + let event = buf.get_event(0).unwrap(); > + let ts_rising = event.get_timestamp(); > + assert_eq!(event.get_event_type().unwrap(), LineEdgeEvent::Rising); > + assert_eq!(event.get_line_offset(), GPIO); > + > + // Falling event > + config > + .request() > + .wait_edge_event(Duration::from_secs(1)) > + .unwrap(); > + > + assert_eq!( > + config > + .request() > + .read_edge_event(&buf, buf.get_capacity()) > + .unwrap(), > + 1 > + ); > + assert_eq!(buf.get_num_events(), 1); > + > + let event = buf.get_event(0).unwrap(); > + let ts_falling = event.get_timestamp(); > + assert_eq!(event.get_event_type().unwrap(), LineEdgeEvent::Falling); > + assert_eq!(event.get_line_offset(), GPIO); > + > + // No events available > + assert_eq!( > + config > + .request() > + .wait_edge_event(Duration::from_millis(100)) > + .unwrap_err(), > + ChipError::OperationTimedOut > + ); > + > + assert!(ts_falling > ts_rising); > + } > + > + #[test] > + fn rising_edge() { > + const GPIO: u32 = 6; > + let buf = EdgeEventBuffer::new(0).unwrap(); > + let mut config = TestConfig::new(NGPIO).unwrap(); > + config.rconfig(Some(&[GPIO])); > + config.lconfig_edge(Some(Edge::Rising)); > + config.request_lines().unwrap(); > + > + // Generate events > + trigger_falling_and_rising_edge(config.sim(), GPIO); > + > + // Rising event > + config > + .request() > + .wait_edge_event(Duration::from_secs(1)) > + .unwrap(); > + > + assert_eq!( > + config > + .request() > + .read_edge_event(&buf, buf.get_capacity()) > + .unwrap(), > + 1 > + ); > + assert_eq!(buf.get_num_events(), 1); > + > + let event = buf.get_event(0).unwrap(); > + assert_eq!(event.get_event_type().unwrap(), LineEdgeEvent::Rising); > + assert_eq!(event.get_line_offset(), GPIO); > + > + // No events available > + assert_eq!( > + config > + .request() > + .wait_edge_event(Duration::from_millis(100)) > + .unwrap_err(), > + ChipError::OperationTimedOut > + ); > + } > + > + #[test] > + fn falling_edge() { > + const GPIO: u32 = 7; > + let buf = EdgeEventBuffer::new(0).unwrap(); > + let mut config = TestConfig::new(NGPIO).unwrap(); > + config.rconfig(Some(&[GPIO])); > + config.lconfig_edge(Some(Edge::Falling)); > + config.request_lines().unwrap(); > + > + // Generate events > + trigger_falling_and_rising_edge(config.sim(), GPIO); > + > + // Falling event > + config > + .request() > + .wait_edge_event(Duration::from_secs(1)) > + .unwrap(); > + > + assert_eq!( > + config > + .request() > + .read_edge_event(&buf, buf.get_capacity()) > + .unwrap(), > + 1 > + ); > + assert_eq!(buf.get_num_events(), 1); > + > + let event = buf.get_event(0).unwrap(); > + assert_eq!(event.get_event_type().unwrap(), LineEdgeEvent::Falling); > + assert_eq!(event.get_line_offset(), GPIO); > + > + // No events available > + assert_eq!( > + config > + .request() > + .wait_edge_event(Duration::from_millis(100)) > + .unwrap_err(), > + ChipError::OperationTimedOut > + ); > + } > + > + #[test] > + fn edge_sequence() { > + const GPIO: [u32; 2] = [0, 1]; > + let mut config = TestConfig::new(NGPIO).unwrap(); > + config.rconfig(Some(&GPIO)); > + config.lconfig_edge(Some(Edge::Both)); > + config.request_lines().unwrap(); > + > + // Generate events > + trigger_rising_edge_events_on_two_offsets(config.sim(), GPIO); > + > + // Rising event GPIO 0 > + let buf = EdgeEventBuffer::new(0).unwrap(); > + config > + .request() > + .wait_edge_event(Duration::from_secs(1)) > + .unwrap(); > + > + assert_eq!( > + config > + .request() > + .read_edge_event(&buf, buf.get_capacity()) > + .unwrap(), > + 1 > + ); > + assert_eq!(buf.get_num_events(), 1); > + > + let event = buf.get_event(0).unwrap(); > + assert_eq!(event.get_event_type().unwrap(), LineEdgeEvent::Rising); > + assert_eq!(event.get_line_offset(), GPIO[0]); > + assert_eq!(event.get_global_seqno(), 1); > + assert_eq!(event.get_line_seqno(), 1); > + > + // Rising event GPIO 1 > + config > + .request() > + .wait_edge_event(Duration::from_secs(1)) > + .unwrap(); > + > + assert_eq!( > + config > + .request() > + .read_edge_event(&buf, buf.get_capacity()) > + .unwrap(), > + 1 > + ); > + assert_eq!(buf.get_num_events(), 1); > + > + let event = buf.get_event(0).unwrap(); > + assert_eq!(event.get_event_type().unwrap(), LineEdgeEvent::Rising); > + assert_eq!(event.get_line_offset(), GPIO[1]); > + assert_eq!(event.get_global_seqno(), 2); > + assert_eq!(event.get_line_seqno(), 1); > + > + // No events available > + assert_eq!( > + config > + .request() > + .wait_edge_event(Duration::from_millis(100)) > + .unwrap_err(), > + ChipError::OperationTimedOut > + ); > + } > + > + #[test] > + fn multiple_events() { > + const GPIO: u32 = 1; > + let buf = EdgeEventBuffer::new(0).unwrap(); > + let mut config = TestConfig::new(NGPIO).unwrap(); > + config.rconfig(Some(&[GPIO])); > + config.lconfig_edge(Some(Edge::Both)); > + config.request_lines().unwrap(); > + > + // Generate events > + trigger_multiple_events(config.sim(), GPIO); > + > + // Read multiple events > + config > + .request() > + .wait_edge_event(Duration::from_secs(1)) > + .unwrap(); > + > + assert_eq!( > + config > + .request() > + .read_edge_event(&buf, buf.get_capacity()) > + .unwrap(), > + 3 > + ); > + assert_eq!(buf.get_num_events(), 3); > + > + let mut global_seqno = 1; > + let mut line_seqno = 1; > + > + // Verify sequence number of events > + for i in 0..3 { > + let event = buf.get_event(i).unwrap(); > + assert_eq!(event.get_line_offset(), GPIO); > + assert_eq!(event.get_global_seqno(), global_seqno); > + assert_eq!(event.get_line_seqno(), line_seqno); > + > + global_seqno += 1; > + line_seqno += 1; > + } > + } > + > + #[test] > + fn over_capacity() { > + const GPIO: u32 = 2; > + let buf = EdgeEventBuffer::new(2).unwrap(); > + let mut config = TestConfig::new(NGPIO).unwrap(); > + config.rconfig(Some(&[GPIO])); > + config.lconfig_edge(Some(Edge::Both)); > + config.request_lines().unwrap(); > + > + // Generate events > + trigger_multiple_events(config.sim(), GPIO); > + > + // Read multiple events > + config > + .request() > + .wait_edge_event(Duration::from_secs(1)) > + .unwrap(); > + > + assert_eq!( > + config > + .request() > + .read_edge_event(&buf, buf.get_capacity()) > + .unwrap(), > + 2 > + ); > + assert_eq!(buf.get_num_events(), 2); > + } > + } > +} > diff --git a/bindings/rust/tests/info_event.rs b/bindings/rust/tests/info_event.rs > new file mode 100644 > index 000000000000..96d8385deadf > --- /dev/null > +++ b/bindings/rust/tests/info_event.rs > @@ -0,0 +1,126 @@ > +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause > +// > +// Copyright 2022 Linaro Ltd. All Rights Reserved. > +// Viresh Kumar > + > +mod common; > + > +mod info_event { > + use libc::EINVAL; > + use std::sync::Arc; > + use std::thread::{sleep, spawn}; > + use std::time::Duration; > + > + use vmm_sys_util::errno::Error as IoError; > + > + use crate::common::*; > + use libgpiod::{Chip, Direction, Error as ChipError, Event, LineConfig, RequestConfig}; > + > + fn request_reconfigure_line(chip: Arc) { > + spawn(move || { > + sleep(Duration::from_millis(10)); > + > + let lconfig1 = LineConfig::new().unwrap(); > + let rconfig = RequestConfig::new().unwrap(); > + rconfig.set_offsets(&[7]); > + > + let request = chip.request_lines(&rconfig, &lconfig1).unwrap(); > + > + sleep(Duration::from_millis(10)); > + > + let mut lconfig2 = LineConfig::new().unwrap(); > + lconfig2.set_direction_default(Direction::Output); > + > + request.reconfigure_lines(&lconfig2).unwrap(); > + > + sleep(Duration::from_millis(10)); > + }); > + } > + Benefit of the background thread? > + mod watch { > + use super::*; > + const NGPIO: u64 = 8; > + const GPIO: u32 = 7; > + > + #[test] > + fn failure() { > + let sim = Sim::new(Some(NGPIO), None, true).unwrap(); > + let chip = Chip::open(sim.dev_path()).unwrap(); > + > + assert_eq!( > + chip.watch_line_info(NGPIO as u32).unwrap_err(), > + ChipError::OperationFailed("Gpio LineInfo line-info", IoError::new(EINVAL)) > + ); > + > + chip.watch_line_info(3).unwrap(); > + > + // No events available > + assert_eq!( > + chip.wait_info_event(Duration::from_millis(100)) > + .unwrap_err(), > + ChipError::OperationTimedOut > + ); > + } > + > + #[test] > + fn verify() { > + let sim = Sim::new(Some(NGPIO), None, true).unwrap(); > + let chip = Chip::open(sim.dev_path()).unwrap(); > + let info = chip.watch_line_info(GPIO).unwrap(); > + > + assert_eq!(info.get_offset(), GPIO); > + } > + > + #[test] > + fn reconfigure() { > + let sim = Sim::new(Some(NGPIO), None, true).unwrap(); > + let chip = Arc::new(Chip::open(sim.dev_path()).unwrap()); > + let info = chip.watch_line_info(GPIO).unwrap(); > + > + assert_eq!(info.get_direction().unwrap(), Direction::Input); > + > + // Generate events > + request_reconfigure_line(chip.clone()); > + > + // Line requested event > + chip.wait_info_event(Duration::from_secs(1)).unwrap(); > + let event = chip.read_info_event().unwrap(); > + let ts_req = event.get_timestamp(); > + > + assert_eq!(event.get_event_type().unwrap(), Event::LineRequested); > + assert_eq!( > + event.line_info().unwrap().get_direction().unwrap(), > + Direction::Input > + ); > + > + // Line changed event > + chip.wait_info_event(Duration::from_secs(1)).unwrap(); > + let event = chip.read_info_event().unwrap(); > + let ts_rec = event.get_timestamp(); > + > + assert_eq!(event.get_event_type().unwrap(), Event::LineConfigChanged); > + assert_eq!( > + event.line_info().unwrap().get_direction().unwrap(), > + Direction::Output > + ); > + > + // Line released event > + chip.wait_info_event(Duration::from_secs(1)).unwrap(); > + let event = chip.read_info_event().unwrap(); > + let ts_rel = event.get_timestamp(); > + > + assert_eq!(event.get_event_type().unwrap(), Event::LineReleased); > + > + // No events available > + assert_eq!( > + chip.wait_info_event(Duration::from_millis(100)) > + .unwrap_err(), > + ChipError::OperationTimedOut > + ); > + > + // Check timestamps are really monotonic. > + assert!(ts_rel > ts_rec); > + assert!(ts_rec > ts_req); > + } > + } > +} > diff --git a/bindings/rust/tests/line_config.rs b/bindings/rust/tests/line_config.rs > new file mode 100644 > index 000000000000..82879324a7f0 > --- /dev/null > +++ b/bindings/rust/tests/line_config.rs > @@ -0,0 +1,187 @@ > +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause > +// > +// Copyright 2022 Linaro Ltd. All Rights Reserved. > +// Viresh Kumar > + > +mod common; > + > +mod line_config { > + use std::time::Duration; > + > + use libgpiod::{Bias, Direction, Drive, Edge, EventClock, LineConfig}; > + > + mod default { > + use super::*; > + > + #[test] > + fn verify() { > + let lconfig = LineConfig::new().unwrap(); > + > + assert_eq!(lconfig.get_direction_default().unwrap(), Direction::AsIs); > + assert_eq!(lconfig.get_edge_detection_default().unwrap(), Edge::None); > + assert_eq!(lconfig.get_bias_default().unwrap(), Bias::AsIs); > + assert_eq!(lconfig.get_drive_default().unwrap(), Drive::PushPull); > + assert_eq!(lconfig.get_active_low_default(), false); > + assert_eq!( > + lconfig.get_debounce_period_default().unwrap(), > + Duration::from_millis(0) > + ); > + assert_eq!( > + lconfig.get_event_clock_default().unwrap(), > + EventClock::Monotonic > + ); > + assert_eq!(lconfig.get_output_value_default().unwrap(), 0); > + assert_eq!(lconfig.get_overrides().unwrap().len(), 0); > + } > + } The only test in the default mod is verify. Drop the mod and rename the test to default. > + > + mod overrides { > + use super::*; > + > + #[test] > + fn direction() { > + const GPIO: u32 = 0; > + let mut lconfig = LineConfig::new().unwrap(); > + > + lconfig.set_direction_default(Direction::AsIs); > + lconfig.set_direction_override(Direction::Input, GPIO); > + > + assert_eq!(lconfig.direction_is_overridden(GPIO), true); > + assert_eq!( > + lconfig.get_direction_offset(GPIO).unwrap(), > + Direction::Input > + ); > + > + lconfig.clear_direction_override(GPIO); > + assert_eq!(lconfig.direction_is_overridden(GPIO), false); > + assert_eq!(lconfig.get_direction_offset(GPIO).unwrap(), Direction::AsIs); > + } > + > + #[test] > + fn edge_detection() { > + const GPIO: u32 = 1; > + let mut lconfig = LineConfig::new().unwrap(); > + > + lconfig.set_edge_detection_default(Edge::None); > + lconfig.set_edge_detection_override(Edge::Both, GPIO); > + > + assert_eq!(lconfig.edge_detection_is_overridden(GPIO), true); > + assert_eq!(lconfig.get_edge_detection_offset(GPIO).unwrap(), Edge::Both); > + > + lconfig.clear_edge_detection_override(GPIO); > + assert_eq!(lconfig.edge_detection_is_overridden(GPIO), false); > + assert_eq!(lconfig.get_edge_detection_offset(GPIO).unwrap(), Edge::None); > + } > + > + #[test] > + fn bias() { > + const GPIO: u32 = 2; > + let mut lconfig = LineConfig::new().unwrap(); > + > + lconfig.set_bias_default(Bias::AsIs); > + lconfig.set_bias_override(Bias::PullDown, GPIO); > + > + assert_eq!(lconfig.bias_is_overridden(GPIO), true); > + assert_eq!(lconfig.get_bias_offset(GPIO).unwrap(), Bias::PullDown); > + > + lconfig.clear_bias_override(GPIO); > + assert_eq!(lconfig.bias_is_overridden(GPIO), false); > + assert_eq!(lconfig.get_bias_offset(GPIO).unwrap(), Bias::AsIs); > + } > + > + #[test] > + fn drive() { > + const GPIO: u32 = 3; > + let mut lconfig = LineConfig::new().unwrap(); > + > + lconfig.set_drive_default(Drive::PushPull); > + lconfig.set_drive_override(Drive::OpenDrain, GPIO); > + > + assert_eq!(lconfig.drive_is_overridden(GPIO), true); > + assert_eq!(lconfig.get_drive_offset(GPIO).unwrap(), Drive::OpenDrain); > + > + lconfig.clear_drive_override(GPIO); > + assert_eq!(lconfig.drive_is_overridden(GPIO), false); > + assert_eq!(lconfig.get_drive_offset(GPIO).unwrap(), Drive::PushPull); > + } > + > + #[test] > + fn active_low() { > + const GPIO: u32 = 4; > + let mut lconfig = LineConfig::new().unwrap(); > + > + lconfig.set_active_low_default(false); > + lconfig.set_active_low_override(true, GPIO); > + > + assert_eq!(lconfig.active_low_is_overridden(GPIO), true); > + assert_eq!(lconfig.get_active_low_offset(GPIO), true); > + > + lconfig.clear_active_low_override(GPIO); > + assert_eq!(lconfig.active_low_is_overridden(GPIO), false); > + assert_eq!(lconfig.get_active_low_offset(GPIO), false); > + } > + > + #[test] > + fn debounce_period() { > + const GPIO: u32 = 5; > + let mut lconfig = LineConfig::new().unwrap(); > + > + lconfig.set_debounce_period_default(Duration::from_millis(5)); > + lconfig.set_debounce_period_override(Duration::from_millis(3), GPIO); > + > + assert_eq!(lconfig.debounce_period_is_overridden(GPIO), true); > + assert_eq!( > + lconfig.get_debounce_period_offset(GPIO).unwrap(), > + Duration::from_millis(3) > + ); > + > + lconfig.clear_debounce_period_override(GPIO); > + assert_eq!(lconfig.debounce_period_is_overridden(GPIO), false); > + assert_eq!( > + lconfig.get_debounce_period_offset(GPIO).unwrap(), > + Duration::from_millis(5) > + ); > + } > + > + #[test] > + fn event_clock() { > + const GPIO: u32 = 6; > + let mut lconfig = LineConfig::new().unwrap(); > + > + lconfig.set_event_clock_default(EventClock::Monotonic); > + lconfig.set_event_clock_override(EventClock::Realtime, GPIO); > + > + assert_eq!(lconfig.event_clock_is_overridden(GPIO), true); > + assert_eq!( > + lconfig.get_event_clock_offset(GPIO).unwrap(), > + EventClock::Realtime > + ); > + > + lconfig.clear_event_clock_override(GPIO); > + assert_eq!(lconfig.event_clock_is_overridden(GPIO), false); > + assert_eq!( > + lconfig.get_event_clock_offset(GPIO).unwrap(), > + EventClock::Monotonic > + ); > + } > + > + #[test] > + fn output_value() { > + const GPIO: u32 = 0; > + let mut lconfig = LineConfig::new().unwrap(); > + > + lconfig.set_output_value_default(0); > + lconfig.set_output_value_override(1, GPIO); > + lconfig.set_output_values(&[1, 2, 8], &[1, 1, 1]).unwrap(); > + > + for line in [0, 1, 2, 8] { > + assert_eq!(lconfig.output_value_is_overridden(line), true); > + assert_eq!(lconfig.get_output_value_offset(line).unwrap(), 1); > + > + lconfig.clear_output_value_override(line); > + assert_eq!(lconfig.output_value_is_overridden(line), false); > + assert_eq!(lconfig.get_output_value_offset(line).unwrap(), 0); > + } > + } > + } > +} > diff --git a/bindings/rust/tests/line_info.rs b/bindings/rust/tests/line_info.rs > new file mode 100644 > index 000000000000..f6f8f592cc85 > --- /dev/null > +++ b/bindings/rust/tests/line_info.rs > @@ -0,0 +1,90 @@ > +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause > +// > +// Copyright 2022 Linaro Ltd. All Rights Reserved. > +// Viresh Kumar > + > +mod common; > + > +mod line_info { > + use libc::EINVAL; > + use std::time::Duration; > + > + use vmm_sys_util::errno::Error as IoError; > + > + use crate::common::*; > + use libgpiod::{Bias, Chip, Direction, Drive, Edge, Error as ChipError, EventClock}; > + use libgpiod_sys::{GPIOSIM_HOG_DIR_OUTPUT_HIGH, GPIOSIM_HOG_DIR_OUTPUT_LOW}; > + > + const NGPIO: u64 = 8; > + > + mod basic { > + use super::*; > + > + #[test] > + fn verify() { > + const GPIO: u32 = 0; > + const LABEL: &str = "foobar"; > + let sim = Sim::new(Some(NGPIO), None, false).unwrap(); > + sim.set_line_name(GPIO, LABEL).unwrap(); > + sim.hog_line(GPIO, "hog", GPIOSIM_HOG_DIR_OUTPUT_HIGH as i32) > + .unwrap(); > + sim.enable().unwrap(); > + > + let chip = Chip::open(sim.dev_path()).unwrap(); > + let info = chip.line_info(GPIO).unwrap(); > + > + assert_eq!(info.get_offset(), GPIO); > + assert_eq!(info.get_name().unwrap(), LABEL); > + assert_eq!(info.is_used(), true); > + assert_eq!(info.get_consumer().unwrap(), "hog"); > + assert_eq!(info.get_direction().unwrap(), Direction::Output); > + assert_eq!(info.is_active_low(), false); > + assert_eq!(info.get_bias().unwrap(), Bias::Unknown); > + assert_eq!(info.get_drive().unwrap(), Drive::PushPull); > + assert_eq!(info.get_edge_detection().unwrap(), Edge::None); > + assert_eq!(info.get_event_clock().unwrap(), EventClock::Monotonic); > + assert_eq!(info.is_debounced(), false); > + assert_eq!(info.get_debounce_period(), Duration::from_millis(0)); > + > + assert_eq!( > + chip.line_info(NGPIO as u32).unwrap_err(), > + ChipError::OperationFailed("Gpio LineInfo line-info", IoError::new(EINVAL)) > + ); > + } > + } > + > + mod properties { > + use super::*; > + > + #[test] > + fn verify() { > + let sim = Sim::new(Some(NGPIO), None, false).unwrap(); > + sim.set_line_name(1, "one").unwrap(); > + sim.set_line_name(2, "two").unwrap(); > + sim.set_line_name(4, "four").unwrap(); > + sim.set_line_name(5, "five").unwrap(); > + sim.hog_line(3, "hog3", GPIOSIM_HOG_DIR_OUTPUT_HIGH as i32) > + .unwrap(); > + sim.hog_line(4, "hog4", GPIOSIM_HOG_DIR_OUTPUT_LOW as i32) > + .unwrap(); > + sim.enable().unwrap(); > + > + let chip = Chip::open(sim.dev_path()).unwrap(); > + chip.line_info(6).unwrap(); > + > + let info4 = chip.line_info(4).unwrap(); > + assert_eq!(info4.get_offset(), 4); > + assert_eq!(info4.get_name().unwrap(), "four"); > + assert_eq!(info4.is_used(), true); > + assert_eq!(info4.get_consumer().unwrap(), "hog4"); > + assert_eq!(info4.get_direction().unwrap(), Direction::Output); > + assert_eq!(info4.is_active_low(), false); > + assert_eq!(info4.get_bias().unwrap(), Bias::Unknown); > + assert_eq!(info4.get_drive().unwrap(), Drive::PushPull); > + assert_eq!(info4.get_edge_detection().unwrap(), Edge::None); > + assert_eq!(info4.get_event_clock().unwrap(), EventClock::Monotonic); > + assert_eq!(info4.is_debounced(), false); > + assert_eq!(info4.get_debounce_period(), Duration::from_millis(0)); > + } > + } Test that you can read all supported values for all fields. > +} > diff --git a/bindings/rust/tests/line_request.rs b/bindings/rust/tests/line_request.rs > new file mode 100644 > index 000000000000..361ee6318d2e > --- /dev/null > +++ b/bindings/rust/tests/line_request.rs > @@ -0,0 +1,234 @@ > +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause > +// > +// Copyright 2022 Linaro Ltd. All Rights Reserved. > +// Viresh Kumar > + > +mod common; > + > +mod line_request { > + use libc::{EBUSY, EINVAL}; > + > + use vmm_sys_util::errno::Error as IoError; > + > + use crate::common::*; > + use libgpiod::{Bias, Direction, Error as ChipError, LineConfig}; > + use libgpiod_sys::{ > + GPIOSIM_PULL_DOWN, GPIOSIM_PULL_UP, GPIOSIM_VALUE_ACTIVE, GPIOSIM_VALUE_INACTIVE, > + }; > + > + const NGPIO: u64 = 8; > + > + mod invalid_arguments { > + use super::*; > + > + #[test] > + fn no_offsets() { > + let mut config = TestConfig::new(NGPIO).unwrap(); > + config.rconfig(None); > + config.lconfig_raw(); > + > + assert_eq!( > + config.request_lines().unwrap_err(), > + ChipError::OperationFailed("Gpio LineRequest request-lines", IoError::new(EINVAL)) > + ); > + } > + > + #[test] > + fn duplicate_offsets() { > + let mut config = TestConfig::new(NGPIO).unwrap(); > + config.rconfig(Some(&[2, 0, 0, 4])); > + config.lconfig_raw(); > + > + assert_eq!( > + config.request_lines().unwrap_err(), > + ChipError::OperationFailed("Gpio LineRequest request-lines", IoError::new(EBUSY)) > + ); > + } > + > + #[test] > + fn out_of_bound_offsets() { > + let mut config = TestConfig::new(NGPIO).unwrap(); > + config.rconfig(Some(&[2, 0, 8, 4])); > + config.lconfig_raw(); > + > + assert_eq!( > + config.request_lines().unwrap_err(), > + ChipError::OperationFailed("Gpio LineRequest request-lines", IoError::new(EINVAL)) > + ); > + } > + } > + > + mod verify { > + use super::*; > + > + #[test] > + fn custom_consumer() { > + const GPIO: u32 = 2; > + const CONSUMER: &str = "foobar"; > + let mut config = TestConfig::new(NGPIO).unwrap(); > + config.rconfig_consumer(Some(&[GPIO]), Some(CONSUMER)); > + config.lconfig_raw(); > + config.request_lines().unwrap(); > + > + let info = config.chip().line_info(GPIO).unwrap(); > + > + assert_eq!(info.is_used(), true); > + assert_eq!(info.get_consumer().unwrap(), CONSUMER); > + } > + > + #[test] > + fn empty_consumer() { > + const GPIO: u32 = 2; > + let mut config = TestConfig::new(NGPIO).unwrap(); > + config.rconfig(Some(&[GPIO])); > + config.lconfig_raw(); > + config.request_lines().unwrap(); > + > + let info = config.chip().line_info(GPIO).unwrap(); > + > + assert_eq!(info.is_used(), true); > + assert_eq!(info.get_consumer().unwrap(), "?"); > + } > + > + #[test] > + fn read_values() { > + let offsets = [7, 1, 0, 6, 2]; > + let pulls = [ > + GPIOSIM_PULL_UP, > + GPIOSIM_PULL_UP, > + GPIOSIM_PULL_DOWN, > + GPIOSIM_PULL_UP, > + GPIOSIM_PULL_DOWN, > + ]; > + let mut config = TestConfig::new(NGPIO).unwrap(); > + config.set_pull(&offsets, &pulls); > + config.rconfig(Some(&offsets)); > + config.lconfig(Some(Direction::Input), None, None, None, None); > + config.request_lines().unwrap(); > + > + let request = config.request(); > + > + // Buffer is smaller > + let mut values: Vec = vec![0; 4]; > + assert_eq!( > + request.get_values(&mut values).unwrap_err(), > + ChipError::OperationFailed( > + "Gpio LineRequest array size mismatch", > + IoError::new(EINVAL), > + ) > + ); > + > + // Buffer is larger > + let mut values: Vec = vec![0; 6]; > + assert_eq!( > + request.get_values(&mut values).unwrap_err(), > + ChipError::OperationFailed( > + "Gpio LineRequest array size mismatch", > + IoError::new(EINVAL), > + ) > + ); > + > + // Single values read properly > + assert_eq!(request.get_value(7).unwrap(), 1); > + > + // Values read properly > + let mut values: Vec = vec![0; 5]; > + request.get_values(&mut values).unwrap(); > + for i in 0..values.len() { > + assert_eq!( > + values[i], > + match pulls[i] { > + GPIOSIM_PULL_DOWN => 0, > + _ => 1, > + } > + ); > + } > + > + // Subset of values read properly > + let mut values: Vec = vec![0; 3]; > + request.get_values_subset(&[2, 0, 6], &mut values).unwrap(); > + assert_eq!(values[0], 0); > + assert_eq!(values[1], 0); > + assert_eq!(values[2], 1); > + > + // Value read properly after reconfigure > + let mut lconfig = LineConfig::new().unwrap(); > + lconfig.set_active_low_default(true); > + request.reconfigure_lines(&lconfig).unwrap(); > + assert_eq!(request.get_value(7).unwrap(), 0); > + } > + > + #[test] > + fn set_output_values() { > + let offsets = [0, 1, 3, 4]; > + let mut config = TestConfig::new(NGPIO).unwrap(); > + config.rconfig(Some(&offsets)); > + config.lconfig(Some(Direction::Output), Some(1), Some((4, 0)), None, None); > + config.request_lines().unwrap(); > + > + assert_eq!(config.sim().val(0).unwrap(), GPIOSIM_VALUE_ACTIVE); > + assert_eq!(config.sim().val(1).unwrap(), GPIOSIM_VALUE_ACTIVE); > + assert_eq!(config.sim().val(3).unwrap(), GPIOSIM_VALUE_ACTIVE); > + > + // Overriden > + assert_eq!(config.sim().val(4).unwrap(), GPIOSIM_VALUE_INACTIVE); > + > + // Default > + assert_eq!(config.sim().val(2).unwrap(), GPIOSIM_VALUE_INACTIVE); > + } > + > + #[test] > + fn reconfigure_output_values() { > + let offsets = [0, 1, 3, 4]; > + let mut config = TestConfig::new(NGPIO).unwrap(); > + config.rconfig(Some(&offsets)); > + config.lconfig(Some(Direction::Output), Some(0), None, None, None); > + config.request_lines().unwrap(); > + let request = config.request(); > + > + // Set single value > + request.set_value(1, 1).unwrap(); > + assert_eq!(config.sim().val(0).unwrap(), GPIOSIM_VALUE_INACTIVE); > + assert_eq!(config.sim().val(1).unwrap(), GPIOSIM_VALUE_ACTIVE); > + assert_eq!(config.sim().val(3).unwrap(), GPIOSIM_VALUE_INACTIVE); > + assert_eq!(config.sim().val(4).unwrap(), GPIOSIM_VALUE_INACTIVE); > + request.set_value(1, 0).unwrap(); > + assert_eq!(config.sim().val(1).unwrap(), GPIOSIM_VALUE_INACTIVE); > + > + // Set values of subset > + request.set_values_subset(&[4, 3], &[1, 1]).unwrap(); > + assert_eq!(config.sim().val(0).unwrap(), GPIOSIM_VALUE_INACTIVE); > + assert_eq!(config.sim().val(1).unwrap(), GPIOSIM_VALUE_INACTIVE); > + assert_eq!(config.sim().val(3).unwrap(), GPIOSIM_VALUE_ACTIVE); > + assert_eq!(config.sim().val(4).unwrap(), GPIOSIM_VALUE_ACTIVE); > + request.set_values_subset(&[4, 3], &[0, 0]).unwrap(); > + assert_eq!(config.sim().val(3).unwrap(), GPIOSIM_VALUE_INACTIVE); > + assert_eq!(config.sim().val(4).unwrap(), GPIOSIM_VALUE_INACTIVE); > + > + // Set all values > + request.set_values(&[1, 0, 1, 0]).unwrap(); > + assert_eq!(config.sim().val(0).unwrap(), GPIOSIM_VALUE_ACTIVE); > + assert_eq!(config.sim().val(1).unwrap(), GPIOSIM_VALUE_INACTIVE); > + assert_eq!(config.sim().val(3).unwrap(), GPIOSIM_VALUE_ACTIVE); > + assert_eq!(config.sim().val(4).unwrap(), GPIOSIM_VALUE_INACTIVE); > + request.set_values(&[0, 0, 0, 0]).unwrap(); > + assert_eq!(config.sim().val(0).unwrap(), GPIOSIM_VALUE_INACTIVE); > + assert_eq!(config.sim().val(1).unwrap(), GPIOSIM_VALUE_INACTIVE); > + assert_eq!(config.sim().val(3).unwrap(), GPIOSIM_VALUE_INACTIVE); > + assert_eq!(config.sim().val(4).unwrap(), GPIOSIM_VALUE_INACTIVE); > + } > + > + #[test] > + fn set_bias() { > + let offsets = [3]; > + let mut config = TestConfig::new(NGPIO).unwrap(); > + config.rconfig(Some(&offsets)); > + config.lconfig(Some(Direction::Input), None, None, None, Some(Bias::PullUp)); > + config.request_lines().unwrap(); > + config.request(); > + > + // Set single value > + assert_eq!(config.sim().val(3).unwrap(), GPIOSIM_VALUE_ACTIVE); > + } > + } Test reconfigure() failure modes. Test you can reconfigure all values for all attributes (not all values for debounce obviously - just the flags). Similarly for request_lines (ideally in chip.rs) > +} > diff --git a/bindings/rust/tests/request_config.rs b/bindings/rust/tests/request_config.rs > new file mode 100644 > index 000000000000..e914ca8ec887 > --- /dev/null > +++ b/bindings/rust/tests/request_config.rs > @@ -0,0 +1,42 @@ > +// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause > +// > +// Copyright 2022 Linaro Ltd. All Rights Reserved. > +// Viresh Kumar > + > +mod common; > + > +mod request_config { > + use vmm_sys_util::errno::Error as IoError; > + > + use libgpiod::{Error as ChipError, RequestConfig}; > + > + mod verify { > + use super::*; > + > + #[test] > + fn default() { > + let rconfig = RequestConfig::new().unwrap(); > + > + assert_eq!(rconfig.get_offsets().len(), 0); > + assert_eq!(rconfig.get_event_buffer_size(), 0); > + assert_eq!( > + rconfig.get_consumer().unwrap_err(), > + ChipError::OperationFailed("Gpio RequestConfig get-consumer", IoError::new(0)) > + ); > + } > + > + #[test] > + fn initialized() { > + let offsets = [0, 1, 2, 3]; > + const CONSUMER: &str = "foobar"; > + let rconfig = RequestConfig::new().unwrap(); > + rconfig.set_consumer(CONSUMER); > + rconfig.set_offsets(&offsets); > + rconfig.set_event_buffer_size(64); > + > + assert_eq!(rconfig.get_offsets(), offsets); > + assert_eq!(rconfig.get_event_buffer_size(), 64); > + assert_eq!(rconfig.get_consumer().unwrap(), CONSUMER); > + } > + } > +} > -- > 2.31.1.272.g89b43f80a514 > Clippy warnings to fix: $cargo clippy --tests warning: this expression creates a reference which is immediately dereferenced by the compiler --> tests/common/config.rs:103:9 | 103 | &self.chip.as_ref().unwrap() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: change this to: `self.chip.as_ref().unwrap()` | = note: `#[warn(clippy::needless_borrow)]` on by default = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow warning: this expression creates a reference which is immediately dereferenced by the compiler --> tests/common/config.rs:107:9 | 107 | &self.request.as_ref().unwrap() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: change this to: `self.request.as_ref().unwrap()` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow warning: used `assert_eq!` with a literal bool --> tests/line_config.rs:24:13 | 24 | assert_eq!(lconfig.get_active_low_default(), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = note: `#[warn(clippy::bool_assert_comparison)]` on by default = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_config.rs:49:13 | 49 | assert_eq!(lconfig.direction_is_overridden(GPIO), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_config.rs:56:13 | 56 | assert_eq!(lconfig.direction_is_overridden(GPIO), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_config.rs:68:13 | 68 | assert_eq!(lconfig.edge_detection_is_overridden(GPIO), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_config.rs:72:13 | 72 | assert_eq!(lconfig.edge_detection_is_overridden(GPIO), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_config.rs:84:13 | 84 | assert_eq!(lconfig.bias_is_overridden(GPIO), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_config.rs:88:13 | 88 | assert_eq!(lconfig.bias_is_overridden(GPIO), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_config.rs:100:13 | 100 | assert_eq!(lconfig.drive_is_overridden(GPIO), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_config.rs:104:13 | 104 | assert_eq!(lconfig.drive_is_overridden(GPIO), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_config.rs:116:13 | 116 | assert_eq!(lconfig.active_low_is_overridden(GPIO), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_config.rs:117:13 | 117 | assert_eq!(lconfig.get_active_low_offset(GPIO), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_config.rs:120:13 | 120 | assert_eq!(lconfig.active_low_is_overridden(GPIO), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_config.rs:121:13 | 121 | assert_eq!(lconfig.get_active_low_offset(GPIO), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_config.rs:132:13 | 132 | assert_eq!(lconfig.debounce_period_is_overridden(GPIO), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_config.rs:139:13 | 139 | assert_eq!(lconfig.debounce_period_is_overridden(GPIO), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_config.rs:154:13 | 154 | assert_eq!(lconfig.event_clock_is_overridden(GPIO), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_config.rs:161:13 | 161 | assert_eq!(lconfig.event_clock_is_overridden(GPIO), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_config.rs:178:17 | 178 | assert_eq!(lconfig.output_value_is_overridden(line), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_config.rs:182:17 | 182 | assert_eq!(lconfig.output_value_is_overridden(line), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_info.rs:38:13 | 38 | assert_eq!(info.is_used(), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = note: `#[warn(clippy::bool_assert_comparison)]` on by default = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_info.rs:41:13 | 41 | assert_eq!(info.is_active_low(), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_info.rs:46:13 | 46 | assert_eq!(info.is_debounced(), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_info.rs:78:13 | 78 | assert_eq!(info4.is_used(), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_info.rs:81:13 | 81 | assert_eq!(info4.is_active_low(), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_info.rs:86:13 | 86 | assert_eq!(info4.is_debounced(), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_request.rs:75:13 | 75 | assert_eq!(info.is_used(), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = note: `#[warn(clippy::bool_assert_comparison)]` on by default = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: used `assert_eq!` with a literal bool --> tests/line_request.rs:89:13 | 89 | assert_eq!(info.is_used(), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `assert!(..)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison warning: `libgpiod` (test "line_config") generated 21 warnings warning: `libgpiod` (test "request_config") generated 2 warnings (2 duplicates) warning: `libgpiod` (test "info_event") generated 2 warnings (2 duplicates) warning: `libgpiod` (test "line_info") generated 8 warnings (2 duplicates) warning: `libgpiod` (test "chip") generated 2 warnings (2 duplicates) warning: `libgpiod` (test "line_request") generated 4 warnings (2 duplicates) warning: `libgpiod` (test "edge_event") generated 2 warnings (2 duplicates) Finished dev [unoptimized + debuginfo] target(s) in 0.05s Cheers, Kent.