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

Correct paths for favorites in file dialog #1351

Merged
merged 18 commits into from Oct 13, 2020

Conversation

PucklaJ
Copy link
Contributor

@PucklaJ PucklaJ commented Oct 1, 2020

Description:

Uses correct paths for favorite locations for different languages on Linux.
It uses the xdg-user-dir command to determine the location.

Fixes #1248

Checklist:

  • Tests included.
  • Lint and formatter run with no errors.
  • Tests all pass.

Where applicable:

  • Public APIs match existing style.
  • Any breaking changes have a deprecation path or have been discussed.

@PucklaJ
Copy link
Contributor Author

PucklaJ commented Oct 1, 2020

I want to add a test for the favorites, but they are inside a widget.Group. This struct does not export their children, so to test the favorites correctly, the children need to somehow be exported.

@PucklaJ
Copy link
Contributor Author

PucklaJ commented Oct 1, 2020

I added a test by just using the slice returned by loadFavorites.

@PucklaJ PucklaJ force-pushed the file_dialog_favorites_language branch 2 times, most recently from 61bec5a to 6894b38 Compare October 1, 2020 08:28
@andydotxyz
Copy link
Member

Thanks for this. We would need a different approach for darwin as it also is not XDG.
More problematic is that my linux computer does not include the xdg-user-dir command (arch linux).
I read that it functions by finding a user-dirs.dirs file, but that does not exist either.

How universal is this feature? If it is fairly common then maybe we can go forward but with sensible fallbacks for other Unix systems?

@PucklaJ
Copy link
Contributor Author

PucklaJ commented Oct 1, 2020

This will work with any linux distribution that has a DE which follow the freedesktop specification, which means: KDE, Gnome, XFCE and many more(exactly like the solution already posted by the OP).

Accordording to the first answer.

sensible fallbacks for other Unix systems

If the command fails an error is returned and the default one (eg. $HOME/Documents) is used.

We would need a different approach for darwin as it also is not XDG

According to this post these folders are handled similiar to Windows and just show the folder in a different language, but on the file system it is language independent.

@andydotxyz
Copy link
Member

Apologies I misread the code when it comes to the actual lookup.
When it's chunks of code that are replaced based on OS we usually use different files for each variant (the app package has a better example) it's a little easier to read when the linux specific code is in a linux file, though in this case it's XDG rather than linux specifically...

It is unusual for DEs to install these utility executables on some systems - you can see in Arch that this is not a requirement of any of the desktops you listed: https://www.archlinux.org/packages/extra/x86_64/xdg-user-dirs/

@andydotxyz
Copy link
Member

A more robust approach might be to use exec.LookPath to see if xdg-user-dirs is installed. If not then printing lots of errors is not really required.

@PucklaJ
Copy link
Contributor Author

PucklaJ commented Oct 1, 2020

When it's chunks of code that are replaced based on OS we usually use different files for each variant

I actually wanted to do that, but I would have had to copy a lot of functions from file_other.go to file_linux.go.

@PucklaJ PucklaJ force-pushed the file_dialog_favorites_language branch 2 times, most recently from 550efda to 1a8ee43 Compare October 1, 2020 11:50
@andydotxyz
Copy link
Member

andydotxyz commented Oct 1, 2020

but I would have had to copy a lot of functions

I get your point - but there were basically 15 lines of code in 4 small functions.
That file is now 45 linux/xdg specific lines to avoid the small duplication...

@PucklaJ
Copy link
Contributor Author

PucklaJ commented Oct 2, 2020

You got a point. I'll figure something out.

@PucklaJ PucklaJ force-pushed the file_dialog_favorites_language branch from 943c82a to a46869f Compare October 2, 2020 10:59
Copy link
Member

@andydotxyz andydotxyz left a comment

Choose a reason for hiding this comment

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

getFavoriteLocations is not defined for non-linux unix systems like BSD.
You might see that in the app package we use the _xdg extension and use the build rule:

// +build linux openbsd freebsd netbsd
// +build !android

alternatively a file_bsd.go would work, if you think the behavior for BSD and Linux is different.

@andydotxyz
Copy link
Member

Thanks. I just checked on BSD (Not on the travis run) and it's happy now :)

andydotxyz
andydotxyz previously approved these changes Oct 3, 2020
@andydotxyz
Copy link
Member

Please don't force push after a review, it results in the following un-usable change set:

Screenshot 2020-10-06 at 12 05 08

And so PRs must be re-reviewed in full...

btn := f.(*widget.Button)
t.Log(fmt.Sprint("Changing from ", curDir, " to ", btn.Text))
test.Tap(btn)
assert.NotEqual(t, curDir, dlg.dialog.dir)
Copy link
Member

Choose a reason for hiding this comment

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

Would it not be better to assert that the correct directory is now set?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't know the exact name of the directory since it depends on the username and language.

Copy link
Member

Choose a reason for hiding this comment

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

I would have thought it existed in the map returned by favouriteLocations()?
I understand that it might not be a trivial lookup/comparison - but by not doing it you run the risk that this is simply setting the un-localised path which would be a failure and yet this test would pass...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, the paths are inside the map, but using those would be like checking strings against themselves. The unlocalised default paths are used if the xdg-user-dir command doesn't exist or if some other error occurs. The default paths are also used if the xdg-user-dir command returns the home directory. This happens when eg. the documents folder doesn't exist. This is the case for the CI tests.

Copy link
Member

Choose a reason for hiding this comment

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

But this test is testing what happens when you tap the button.
To check that the favourites are created correctly is the remit of another test (one that does not create a file dialog UII).
Testing the dialog's new location against the string representing the location that should have been loaded when a button was pressed seems quite correct to me.
If your concern is that the localisation is not tested if we do that then yes another test can be added. But by ignoring the contents of the string I don't see that anything is being added.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I changed it so that dlg.dialog.dir is checked against getFavoriteLocations.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To check that the favourites are created correctly is the remit of another test

What test is this exactly? I couldn't find a test which is testing the favorites.

Copy link
Member

Choose a reason for hiding this comment

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

I did not mean that it existed, I was more hinting that tests should test one thing, so maybe a test is missing?

Copy link
Member

Choose a reason for hiding this comment

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

I think that this would be wrapped up nicely if we could add a test of the file_xdg contents - do you think that is possible? (clearly they would only run on linux :) )

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I did my best, but it is difficult to test this since the paths depend on the languange and sometimes don't even exist.

dialog/file_test.go Outdated Show resolved Hide resolved
@andydotxyz
Copy link
Member

Thanks for this update, a positive tests seems more complete.
Also good catch on the drive buttons, I had forgotten about them!

Copy link
Member

@andydotxyz andydotxyz left a comment

Choose a reason for hiding this comment

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

I might have misunderstood the new tests, but hopefully my comments help

assert.Equal(t, homeDir, fav)
} else {
assert.Equal(t, homeDir, filepath.Dir(fav))
if _, err := os.Stat(fav); os.IsNotExist(err) {
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand this test sorry.
It seems to iterate expected directories and confirms that they end with the expected string.
But the XDG code exists to make this configurable - so as soon as someone has that set these will fail won't they?

The purpose of testing the favourite location lookup would be to test the wrapper around xdg-user-dir I would think, which is based on environment variables, so can we manipualte them to test the code is working?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The way it works is that xdg-user-dirs-update is run very early in the login phase. This program reads a configuration file, and a set of default directories. It then creates localized versions of these directories in the users home directory and sets up a config file in $(XDG_CONFIG_HOME)/user-dirs.dirs (XDG_CONFIG_HOME defaults to ~/.config) that applications can read to find these directories.

This is from here.

So it's not really about environment variables, but more about a config file. I think this is too "hacky" for me so I will leave it at that.

so as soon as someone has that set these will fail won't they?

The paths are only getting checked against those strings when the folders don't exist. So this test is not testing wether getFavoriteLocations returns the correct paths. It is only checking if the fallback paths are correct.

Copy link
Member

Choose a reason for hiding this comment

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

Ah I understand thanks. I was struggling to follow the code - I played with it a bit, maybe some of these changes can help? Let me know what you think.

func TestFavoriteLocations(t *testing.T) {
	favoriteLocations, _ := getFavoriteLocations()

	// This is a map containing the base name
	// of every key that should be in favoriteLocations
	expected := map[string]string{
		"Home":      "",
		"Documents": "Documents",
		"Downloads": "Downloads",
	}

	homeDir, err := os.UserHomeDir()
	assert.Nil(t, err)

	for name, subdir := range expected {
		fav, ok := favoriteLocations[name]
		if !ok {
			t.Errorf("missing favourite location", name)
			continue
		}

		if subdir == "" {
			assert.Equal(t, homeDir, fav)
		} else {
//			assert.Equal(t, homeDir, filepath.Dir(fav)) // I don't think this assertion must be true, the user could specify a different parent directory
			_, err := os.Stat(fav)
			if err == nil {
				continue // folder found
			}
			if !os.IsNotExist(err) {
				t.Errorf("failed to read directory %s", fav)
				continue
			}
			fallbackName := filepath.Base(fav)
			if !strings.EqualFold(subdir, fallbackName) {
				t.Errorf("%s should equal fold with %s", subdir, fallbackName)
			}
		}
	}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So the only thing that's different here is that

assert.Equal(t, homeDir, filepath.Dir(fav))

has been removed. Right?

@andydotxyz
Copy link
Member

I probably should have said if the XDG tests are proving difficult then don't worry, I can merge this in and complete it myself.
Platform specifics can be a pain.

@PucklaJ
Copy link
Contributor Author

PucklaJ commented Oct 12, 2020

I rewrote most of the code because of #1379. I used fyne.ListableURI everywhere where it should be used. But this needs a rebase and a force push of course. So just tell me when you are ready for that.

@andydotxyz
Copy link
Member

Hi. In general we would prefer a merge into the PR with the conflict resolution commit.
However in this instance I can see that the majority of the code has changed, so go ahead.

@PucklaJ PucklaJ force-pushed the file_dialog_favorites_language branch from 982eb4a to b7ba91a Compare October 12, 2020 11:26
@andydotxyz
Copy link
Member

All of the Linux builds are failing so I don't think it's random error @PucklaMotzer09

@PucklaJ
Copy link
Contributor Author

PucklaJ commented Oct 13, 2020

Now that I use fyne.ListableURI every favorite location has to exist. But the folders can be missing on some systems, so I can't really test them now.

@andydotxyz
Copy link
Member

Looking at the latest change I see that you've removed an error when the favourite does not exist but also checking that an existing favourite cannnot be loaded.
It seems strange that both would be removed, consider the user experience - the left-panel should show those locations that we have found I think? So that list works from the favourite locations right? Then the end of the test that tries to find a favourite location should surely still pass, because it being in the list means that we found it?

(Apologies if that is not a correct representation of the current code, I was thinking out loud how it maybe should work).
What do you think?

@PucklaJ
Copy link
Contributor Author

PucklaJ commented Oct 13, 2020

Every favorite location that has been found and exists will be added to the list. Every path that doesn't exist does not appear on the left panel. This happens because getFavoriteLocations now returns fyne.ListableURI and you can only create a ListableURI from an URI if the path exists. I think this behaviour is reasonable, but this makes it difficult to test since every system can have different paths or no paths at all.

@andydotxyz
Copy link
Member

I think that sounds great, but if that is the case then why did the second part of the test need to be removed?
If we are only checking against existing favourite locations then we should be able to test for them...

@andydotxyz
Copy link
Member

I think maybe we are not on the same page. I was asking that we re-instate some of the tests that should still pass, but now you have removed more?

@PucklaJ
Copy link
Contributor Author

PucklaJ commented Oct 13, 2020

If a path doesn't exist then it doesn't get added to the favoriteLocations map. If I would add it to the map than that value would be nil, since I can't create a ListableURI from a non existing path. So the only favorite location we actually can test is Home. There is no need to check if the paths exist since we already know that they do.

@PucklaJ
Copy link
Contributor Author

PucklaJ commented Oct 13, 2020

but now you have removed more?

I removed them because they were meaningless.

@PucklaJ
Copy link
Contributor Author

PucklaJ commented Oct 13, 2020

Yes we should think about how to test them properly. The tests just didn't check something meaningful as they were.

@andydotxyz
Copy link
Member

I thought the tests were confirming that the custom directory locations did in fact exist.
I appreciate that this may not have been meaningful on Travis, but surely they deserved to remain for the plethora of Linux devices that this is tested on during development?

@PucklaJ
Copy link
Contributor Author

PucklaJ commented Oct 13, 2020

Yes you are right. I forgot about the other platforms and the drives. I added a check for the existance of the directories. But TestFavoriteLocations is pretty meaningless right now.

@andydotxyz andydotxyz merged commit 26427e2 into fyne-io:develop Oct 13, 2020
@PucklaJ PucklaJ deleted the file_dialog_favorites_language branch October 14, 2020 14:46
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.

None yet

2 participants