Require a field as part of a Rust trait - selenium-webdriver

Is it possible to require that a struct have a particular field as part of a trait? I am doing some web automation in Rust with the thirtyfour_sync crate. I want to write some traits with default implementations for page objects that will implement them. Basically, I know for a fact that every struct that is going to implement this trait will have a field called "driver" that holds a reference to a WebDriver struct. I want to use this driver field in my default implementation of the trait.
error[E0609]: no field `driver` on type `&Self`
--> src\base_order_details.rs:13:30
|
10 | / pub trait BaseOrderDetails {
11 | |
12 | | fn oid(&self) -> WebDriverResult<String> {
13 | | let oid_title = self.driver.find_element(By::XPath("//*[text()=\"Order ID:\"]"))?;
| | ^^^^^^
... |
Is there a way to let the compiler know that anything implementing this trait will have a field driver of type &WebDriver?

I discovered the answer to my question while drafting it. No, you cannot access fields from traits. As a solution, I have added a get_driver method to the trait and used it within the default implementation, so the user can simply implement the get_driver method and default the rest.
pub trait BaseOrderDetails {
fn get_driver(&self) -> &WebDriver;
fn oid(&self) -> WebDriverResult<String> {
let oid_title = self.get_driver().find_element(By::XPath("//*[text()=\"Order ID:\"]"))?;
// do some other stuff
I found this solution in the Rust Book chapter on traits, under Default Implementations: https://doc.rust-lang.org/book/ch10-02-traits.html

Related

How do I get a dynamic type from a dynamic array in typescript?

I've searched for a solution already and found const assertions but Typescript gives me a type error that I can only use const assertions on certain types... Probably referring to that the array I want to assert is not set in the same file but rather will be set by the user who will be using my module. To explain what I mean I have some code below.
The following code block is the file HighLight.ts for example.
type Languages = "javascript" | "typescript" | "json" | "java" | "kotlin" | "python";
export default class HighLight {
private languages: Languages | Languages[];
constructor({ languages }: { languages: Languages | Languages[] }) {
this.languages = <const>languages;
}
}
And I import it in the index.ts file
import HighLight from "HighLight.ts";
new HighLight(["javascript", "typescript"])
To give some more context, I want to create a module that can highlight code using highlight.js and have it as a pure string which you can print to the console, essentially a port of highlight.js for nodejs but purely for console applications.
Because I want my implementation to import all languages only as needed (like highlight.js) the user has to provide a list of languages they plan on highlighting later on. I've figured out the importing part already but I haven't attached that code as I think it is irrelevant to this problem.
With that out of the way, I wanted to create a highlight method which takes in the code and the language. It would be nice if languages is restricted to only the languages you've given the constructor when creating an instance. What I thought to be an easy task with a const assertion turned out to be hard. A const assertion in this scenario doesn't work as the array/string is unknown at the moment but later set by the user when calling the constructor... I also noticed that if the array is statically typed but in a different file a const assertion also does not work sadly.
Is there a different way of getting that type for the highlight method?
type Languages = "javascript" | "typescript" | "json" | "java" | "kotlin" | "python";
export default class HighLight<L extends Languages> {
private languages: L | L[];
constructor({ languages }: { languages: L | L[] }) {
this.languages = languages;
}
}
let l = new HighLight({languages: 'javascript'})
// ^? let l: HighLight<"javascript">

How do Pact interfaces provide abstraction similar to Haskell type classes?

The Pact documentation mentions that interfaces in Pact allow for abstraction similar to Haskell's type classes:
When a module issues an implements, then that module is said to ‘implement’ said interface, and must provide an implementation . This allows for abstraction in a similar sense to Java’s interfaces, Scala’s traits, Haskell’s typeclasses or OCaML’s signatures. Multiple interfaces may be implemented in a given module, allowing for an expressive layering of behaviors.
I understand that you can write an interface (this corresponds with declaring a class in Haskell), and then you can implement the interface for one or more modules (this corresponds with an instance in Haskell). For example:
-- This corresponds with declaring an interface
class Show a where
show :: a -> String
-- This corresponds with implementing an interface
instance Show Bool where
show True = "True"
show False = "False"
However, the great value of a Haskell type class is that you can then abstract over it. You can write a function that takes any value so long as it is an instance of Show:
myFunction :: (Show a) => a -> ...
myFunction = ...
What is the corresponding concept in Pact? Is there a way to accept any module as a dependency, so long as it implements the interface? If not, how does this open up abstraction "in a similar sense to Haskell's type classes"?
I think your question may be conflating typeclasses with type variables and universal quantification. Typeclasses give you a common interface like show that can be used on any type (or in this case, module) that supports them. Universal quantification lets you write generic algorithms that work for any Show instance.
Pact provides the former, but not the latter. The main utility is in giving your module a template to work against, and anyone who knows the interface will be able to use your module. This makes "swapping implementations" possible, but doesn't open the door to "generic algorithms". For that we'd need some way of saying "For all modules that implement interface"...
UPDATE: As per Stuart Popejoy's comment, this sort of abstraction can indeed be achieved using modrefs. Here is an example of a module that implements a generic method over any module implementing a certain interface:
(interface iface
(defun op:integer (arg:string)))
(module impl1 G
(defcap G () true)
(implements iface)
(defun op:integer (arg:string) (length arg)))
(module impl2 G
(defcap G () true)
(implements iface)
(defun op:integer (arg:string) -1))
(module app G
(defcap G () true)
(defun go:integer (m:module{iface} arg:string)
(m::op arg)))
(expect "impl1" 5 (app.go impl1 "hello"))
(expect "impl2" -1 (app.go impl2 "hello"))

How is inference by enumeration done on bayesian networks?

For instance, if given the following Bayesian network and probabilities how would I find P(BgTV | not(GfC). I attempted to do so by simply using the equivalence that P(A|B) = P(A and B)/P(B) but that resulted in me having a value of 200% which is not possible. Do I need to treat George_feeds_cat as a dependent event as per the network and use what I know from baseball_game_on_TV and George_watches_TV to calculate the odds? Any guidance would be much appreciated!
Indeed, you need all the parameters for answering your question (oCF seems to be independent from BgTV and GwTV but knowing GfC, this is not the case anymore).
Using the columns, instead of the symbols, you want :
P(A|C)=P(A,C)/P(C)=sum_{B,D} P(A,B,C,D) / sum_{A,B,D} P(A,B,C,D)
with the joint distribution factorized using the BN
P(A,B,C,D)=P(A)*P(B|A)*P(C)*P(D|C,B)
In Python using the package pyAgrum, you would write :
# model
import pyAgrum as gum
bn=gum.fastBN("BgTV->GwTV->GfC<-oCF")
# where do those numbers come from ? :-)
bn.cpt("BgTV").fillWith([1-0.3041096,0.3041096])
bn.cpt("oCF").fillWith([1-0.169863,0.169863])
bn.cpt("GwTV")[{"BgTV":0}]=[1-0.1181102,0.1181102]
bn.cpt("GwTV")[{"BgTV":1}]=[1-0.9279279,0.9279279]
bn.cpt("GfC")[{"GwTV":0,"oCF":0}]=[1-0.9587629,0.9587629]
bn.cpt("GfC")[{"GwTV":0,"oCF":1}]=[1-0.3157895,0.3157895]
bn.cpt("GfC")[{"GwTV":1,"oCF":0}]=[1-0.706422,0.706422]
bn.cpt("GfC")[{"GwTV":1,"oCF":1}]=[1-0.0416667,0.0416667]
# compute
joint=bn.cpt("BgTV")*bn.cpt("GwTV")*bn.cpt("GfC")*bn.cpt("oCF")
joint.margSumIn(["GfC","BgTV"])/joint.margSumIn("GfC")
which should give you
|| BgTV |
GfC ||0 |1 |
------||---------|---------|
0 || 0.5159 | 0.4841 |
1 || 0.7539 | 0.2461 ||
Where you see that P(BgTV=1|GfC=0)=48.41%
Using a notebook, the model :
And the inference (using another method with junction tree) :

Rust all write to file methods give 'method not found in std::io::BufReader<std::fs::File>'

I've been following tutorials, accepted answers, and the docs. They never worked for me since the beginning of learning, and now I'm stuck at it again.
Imports:
use std::io::prelude::*;
use std::fs::{File, OpenOptions};
use std::io::Read;
use std::io::BufReader;
use std::io::BufRead;
use std::io::Write;
Code:
let mut file_help = OpenOptions::new().append(true).create_new(true).open("n.txt").expect(".");
let mut file_help = BufReader::new(file_help);
Loop for vec:
for i in d_call {file_help.write(format!("{}\n",i))};
In-loop variants that are giving out same errormethod not found in `std::io::BufReader<std::fs::File>:
file_help.write_all(format!("{}\n",i))
write!(file_help, "{}\n",i)
file_help.write(format!("{}\n",i.to_string()))
writeln!(file_help, "{}", i.to_string())
error[E0599]: no method named `write` found for struct `BufReader` in the current scope
--> src/main.rs:21:19
|
21 | file_help.write(format!("{}\n", i.to_string()))
| ^^^^^ method not found in `BufReader<File>`
Playground.
The issue is actually quite simple. You are trying to write data to a BufReader. It can buffer file reads, but does not implement any write functionality. You likely want to use a std::io::BufWriter instead.

Combining multiple external datasets with cucumber/selenium test environments

When developing automated tests using cucumber and selenium webdriver in java, I use excel spreadsheets as datasets for the gherkin scenarios instead of the traditional Examples tables, using a simple table with only the row numbers in my feature files. This works very well when doing tests that only make use of data from one spreadsheet at a time, but when implementing tests that make use of multiple spreadsheets, how does one ensure the it iterates over every combination.
For example, when testing multiple configurations and their impact on the main interface, I provide the configuration data, let's say 3 combinations of different configurations, using the first spreadsheet, and in my gherkin feature I only enter the row numbers and use the code to handle the actual reading of data.
When the user uses configuration from row <ExcelRow>
...
Examples:
| ExcelRow |
| 1 |
| 2 |
| 3 |
The problem arises when I want to test such configurations with different combinations of inputs in the main interface, also provided via a separate excel spreadsheet. I want configuration from row 1 to be run with all rows from the second spreadsheet, before moving on to row 2's configuration and so on.
Manually using the examples table to do the combinations does the job when working with smaller data sets
Examples:
| ConfigRow | InputRow |
| 1 | 1 |
| 1 | 2 |
| 2 | 1 |
| 2 | 2 |
| 3 | 1 |
| 3 | 2 |
The problem arises when using very large datasets, where the examples table starts to clutter the feature file despite only containing the row numbers.
I tried implementing the actual input testing as a single step that loops over the entire excel spreadsheet for each configuration, but that forced me to do my assertions in the same loop and not in the Then step.
If you want to mention only config row in feature file and you want that some other rows to be executed for each config row then you may want to utilize cucumber-guice and make it #ScenarioScoped . Cucumber-guice can initialize same classes for each scenario independently. You would need these dependencies in your pom
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-guice</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>4.2.3</version>
<scope>test</scope>
</dependency>
Then , in a global class you can do
import io.cucumber.guice.ScenarioScoped;
#ScenarioScoped
public class Global {
public Helpers help;
//constructor
public Global() {
//helper class would contain code that does all the second excel sheet work
help = new Helpers();
}
}
In step def you can do
//import Global and guice dependencies
import yourPackage.Global;
import com.google.inject.Inject;
...
...
public class stepDef {
#Inject
Global global;
#When ("the user uses configuration from row {int}")
public void useConfigs(){
global.help.doSomeExcelWork();
}
#Then ("I assert from excel sheet")
public void doAssertions(){
//do assertions here. These
global.help.doAssertion();
}
}
Your helper class could be something like this
public class Helper {
public void doSomeExcelWork(){
//do excel work
}
public void doAssertion(){
//return values for your assertions
}
}
Your feature file would look like
When the user uses configuration from row <ExcelRow>
Examples:
| ExcelRow |
| 1 |
| 2 |
Then I assert from excel sheet
Now , for all your examples (scenarios) global would be injected independently and the then statement also would be called for each example row
I am not sure if that is possible to do via Cucumber. You may try searching for Cucumber Java dynamic examples generation like here.
I just would like to question if Cucumber/Gherkin are the right tools for what you wanted to achieve. The primary goal of Gherkin / Cucumber / Specflow scenarios is demonstrate the behavior of the system to anyone reading the feature file. So hiding the data in "linked" files can be accepted if they hold a complex piece of data which is as a single unit, provided the file name demonstrates what is special about the data inside.
What you might be looking for are Parameterized Tests and Data Providers that are available in JUnit 5 and TestNG 2, 3. If you write automation framework in the way that Cucumber, or other test framework becomes only a thin wrapper around it which "assembles" the test, you can generate tests on the fly.
For example your step: "When the user uses configuration from row", becomes
public void whenUserUsesConfiguration(SutConfiguration configuration) {
// your configuration setup goes here
// but you do not read configuration from file in this method
}
Method above can be used in both Cucumber steps and JUnit/TestNG test without loosing any readability, or understandability.
By splitting your tests into two parts, one for understanding general system behavior and accessible to all stakeholders, and the one that check lots of small nuances, but both using the same framework will allow you to have greater flexibility, and more pleasant development experience.

Resources