Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move test harness to separate package #110

Open
wants to merge 65 commits into
base: master
Choose a base branch
from
Open

Conversation

sonro
Copy link
Collaborator

@sonro sonro commented Jul 23, 2024

The test utilities, proposed in #58, shouldn't just be in one test suite. The harness can, and should, be used across the project. It could even be used outside of dotenvy entirely.

This PR creates a new workspace member dotenvy_test_util - which contains the test harness along with its documentation.


The new test suite itself is nearly finished, see #111.

Copy link
Owner

@allan2 allan2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see this being very useful in creating test files, test text, and testing more complicated cases.

I would prefer if the usage of custom assert functions were minimized. Fallible functions such as Efb::add_env_file should return Result. The tests themselves can be written a Result signature as well. A custom error type may be helpful here.

}

/// Add a string without a newline
pub fn add_str(&mut self, s: &str) -> &mut Self {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

push_str may be more conventional.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we change to push or append then the other "add" functions should follow suit.

So we'd have:

  • push_vars
  • push_var
  • push_str
  • push_strln
  • push_bytes
  • push_byte

Or the append version.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think less is better. I think of Efb as a wrapper around a vector of bytes, with one convenience function, add_key_value.

We shouldn't try to do too much by supporting both byte functions and string functions.

My suggestion is to implement some of the Vec functions:
add_byte -> push
add_bytes -> extend_from_slice
add_str -> extend_from_slice(s.as_bytes())
add_strln -> can add a string and push the newline char

And implement the convenience functions:
add_key_value -> add_var
add_vars -> use a for loop with add_var

Test writers can use the Vec API and the string-to-byte conversions they are already familiar with.

Copy link
Collaborator Author

@sonro sonro Aug 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, simpler is better. The majority of use cases would be pushing &str, so I do think keeping that as push_str is worthwhile. Therefore, push_bytes makes sense as a corollary.

add_vars does have a performance improvement to looping over add_var. Looping will perform multiple allocations. BUT, I will concede that the majority of new tests will only have 3 vars max in an env file.

So I will remove it.

test_util/src/tests/envfile_builder.rs Outdated Show resolved Hide resolved
test_util/src/tests/envfile_builder.rs Outdated Show resolved Hide resolved
test_util/src/envfile.rs Outdated Show resolved Hide resolved
///
/// Represented as bytes to allow for advanced manipulation and BOM testing.
#[derive(Debug, Default)]
pub struct EnvFileBuilder {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of the Builder suffix, since it's too commonly used in the other context, i.e., describing the API design. I would suggest EnvFileAdv, with "Adv" short for Advanced. Perhaps you can think of something better.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some options:

  • EnvFileAdvCreator
  • EnvFileMaker
  • AdvancedEnvFile

I quite like the last one. The struct can be passed into init_with_env_file and add_env_file, so semantically it makes sense.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am good with either AdvancedEnvFile or AdvEnvFile. I personally prefer shorter names; they are more adventurous (AdventurousEnvFile?)

Copy link
Owner

@allan2 allan2 Jul 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Efb is such a good acronym though. EnvFileBuilder has grown on me!

Copy link
Collaborator Author

@sonro sonro Aug 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am currently simplifying this crate. Removing the "default" code I have come to realise this should just be called EnvFileContents and be the primary way one is constructed.

A String, &str, Vec<u8>, &[u8] or EnvFileBuilder, can already be passed to TestEnv::add_env_file. So why not just call this EnvFileContents as it will be the only way of constructing one besides just using the primitive types. Plus that's exactly what it is.

efc is a pretty good acronym too ;)

test_util/src/testenv.rs Outdated Show resolved Hide resolved
test_util/src/testenv.rs Outdated Show resolved Hide resolved
@sonro
Copy link
Collaborator Author

sonro commented Jul 31, 2024

Fallible functions such as Efb::add_env_file should return Result. The tests themselves can be written a Result signature as well. A custom error type may be helpful here.

Understood, I'll go ahead and add an error type.

You're right for wanting the failed states to be as descriptive as possible. When these utilities were part of the test harness, it made sense to have custom panic messages. Now it is a separate package: errors are far more appropriate.

I would prefer if the usage of custom assert functions were minimized.

Perhaps if we removed the default TestEnv settings the need for custom asserts would be minimized even further. This allows users to set defaults and custom asserts as they see fit.

To match env_var
- Clone
- PartialEq
- Eq

- PartialEq to String and &str
- PartialEq to Vec<u8> and &[u8]

- AsRef<[u8]>
@allan2
Copy link
Owner

allan2 commented Jul 31, 2024

@sonro I added my comments on Efb above. But if we are adding a safe API, then I am sure this harness will look different.

Would you rather wait for that before updating this PR further?

@sonro
Copy link
Collaborator Author

sonro commented Aug 1, 2024

@sonro I added my comments on Efb above. But if we are adding a safe API, then I am sure this harness will look different.

Would you rather wait for that before updating this PR further?

The new API can still be tested with these utilities too!

#[test]
fn existing_var_no_env_file() {
    let mut testenv = TestEnv::init();
    testenv.add_env_var("TEST_KEY", "test_val");
    test_in_env(&testenv, || {
        let safe_vars = dotenvy::load_all().unwrap(); // or whatever the api ends up being
        let actual = safe_vars.get("TEST_KEY").unwrap();
        assert_eq!("test_val", actual");
    });
}

Plus we need it to thoroughly test the existing API - deprecated or not. We shouldn't mind unsafety within the test harness as it already uses a mutex for thread safety.

Copy link

github-actions bot commented Aug 1, 2024

Code Coverage

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants