github.com/rigado/snapd@v2.42.5-go-mod+incompatible/wrappers/desktop_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2014-2015 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package wrappers_test
    21  
    22  import (
    23  	"fmt"
    24  	"io/ioutil"
    25  	"os"
    26  	"path/filepath"
    27  
    28  	. "gopkg.in/check.v1"
    29  
    30  	"github.com/snapcore/snapd/dirs"
    31  	"github.com/snapcore/snapd/osutil"
    32  	"github.com/snapcore/snapd/snap"
    33  	"github.com/snapcore/snapd/snap/snaptest"
    34  	"github.com/snapcore/snapd/testutil"
    35  	"github.com/snapcore/snapd/wrappers"
    36  )
    37  
    38  type desktopSuite struct {
    39  	testutil.BaseTest
    40  	tempdir string
    41  
    42  	mockUpdateDesktopDatabase *testutil.MockCmd
    43  }
    44  
    45  var _ = Suite(&desktopSuite{})
    46  
    47  func (s *desktopSuite) SetUpTest(c *C) {
    48  	s.BaseTest.SetUpTest(c)
    49  	s.BaseTest.AddCleanup(snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {}))
    50  	s.tempdir = c.MkDir()
    51  	dirs.SetRootDir(s.tempdir)
    52  
    53  	s.mockUpdateDesktopDatabase = testutil.MockCommand(c, "update-desktop-database", "")
    54  }
    55  
    56  func (s *desktopSuite) TearDownTest(c *C) {
    57  	s.BaseTest.TearDownTest(c)
    58  	s.mockUpdateDesktopDatabase.Restore()
    59  	dirs.SetRootDir("")
    60  }
    61  
    62  var desktopAppYaml = `
    63  name: foo
    64  version: 1.0
    65  apps:
    66      foobar:
    67  `
    68  
    69  var mockDesktopFile = []byte(`
    70  [Desktop Entry]
    71  Name=foo
    72  Icon=${SNAP}/foo.png`)
    73  var desktopContents = ""
    74  
    75  func (s *desktopSuite) TestAddPackageDesktopFiles(c *C) {
    76  	expectedDesktopFilePath := filepath.Join(dirs.SnapDesktopFilesDir, "foo_foobar.desktop")
    77  	c.Assert(osutil.FileExists(expectedDesktopFilePath), Equals, false)
    78  
    79  	info := snaptest.MockSnap(c, desktopAppYaml, &snap.SideInfo{Revision: snap.R(11)})
    80  
    81  	// generate .desktop file in the package baseDir
    82  	baseDir := info.MountDir()
    83  	err := os.MkdirAll(filepath.Join(baseDir, "meta", "gui"), 0755)
    84  	c.Assert(err, IsNil)
    85  
    86  	err = ioutil.WriteFile(filepath.Join(baseDir, "meta", "gui", "foobar.desktop"), mockDesktopFile, 0644)
    87  	c.Assert(err, IsNil)
    88  
    89  	err = wrappers.AddSnapDesktopFiles(info)
    90  	c.Assert(err, IsNil)
    91  	c.Assert(osutil.FileExists(expectedDesktopFilePath), Equals, true)
    92  	c.Assert(s.mockUpdateDesktopDatabase.Calls(), DeepEquals, [][]string{
    93  		{"update-desktop-database", dirs.SnapDesktopFilesDir},
    94  	})
    95  }
    96  
    97  func (s *desktopSuite) TestRemovePackageDesktopFiles(c *C) {
    98  	mockDesktopFilePath := filepath.Join(dirs.SnapDesktopFilesDir, "foo_foobar.desktop")
    99  
   100  	err := os.MkdirAll(dirs.SnapDesktopFilesDir, 0755)
   101  	c.Assert(err, IsNil)
   102  	err = ioutil.WriteFile(mockDesktopFilePath, mockDesktopFile, 0644)
   103  	c.Assert(err, IsNil)
   104  	info, err := snap.InfoFromSnapYaml([]byte(desktopAppYaml))
   105  	c.Assert(err, IsNil)
   106  
   107  	err = wrappers.RemoveSnapDesktopFiles(info)
   108  	c.Assert(err, IsNil)
   109  	c.Assert(osutil.FileExists(mockDesktopFilePath), Equals, false)
   110  	c.Assert(s.mockUpdateDesktopDatabase.Calls(), DeepEquals, [][]string{
   111  		{"update-desktop-database", dirs.SnapDesktopFilesDir},
   112  	})
   113  }
   114  
   115  func (s *desktopSuite) TestParallelInstancesRemovePackageDesktopFiles(c *C) {
   116  	mockDesktopFilePath := filepath.Join(dirs.SnapDesktopFilesDir, "foo_foobar.desktop")
   117  	mockDesktopInstanceFilePath := filepath.Join(dirs.SnapDesktopFilesDir, "foo+instance_foobar.desktop")
   118  
   119  	err := os.MkdirAll(dirs.SnapDesktopFilesDir, 0755)
   120  	c.Assert(err, IsNil)
   121  	err = ioutil.WriteFile(mockDesktopFilePath, mockDesktopFile, 0644)
   122  	c.Assert(err, IsNil)
   123  	err = ioutil.WriteFile(mockDesktopInstanceFilePath, mockDesktopFile, 0644)
   124  	c.Assert(err, IsNil)
   125  	info, err := snap.InfoFromSnapYaml([]byte(desktopAppYaml))
   126  	c.Assert(err, IsNil)
   127  
   128  	err = wrappers.RemoveSnapDesktopFiles(info)
   129  	c.Assert(err, IsNil)
   130  	c.Assert(osutil.FileExists(mockDesktopFilePath), Equals, false)
   131  	c.Assert(s.mockUpdateDesktopDatabase.Calls(), DeepEquals, [][]string{
   132  		{"update-desktop-database", dirs.SnapDesktopFilesDir},
   133  	})
   134  	// foo+instance file is still there
   135  	c.Assert(osutil.FileExists(mockDesktopInstanceFilePath), Equals, true)
   136  
   137  	// restore the non-instance file
   138  	err = ioutil.WriteFile(mockDesktopFilePath, mockDesktopFile, 0644)
   139  	c.Assert(err, IsNil)
   140  
   141  	s.mockUpdateDesktopDatabase.ForgetCalls()
   142  
   143  	info.InstanceKey = "instance"
   144  	err = wrappers.RemoveSnapDesktopFiles(info)
   145  	c.Assert(err, IsNil)
   146  	c.Assert(osutil.FileExists(mockDesktopInstanceFilePath), Equals, false)
   147  	c.Assert(s.mockUpdateDesktopDatabase.Calls(), DeepEquals, [][]string{
   148  		{"update-desktop-database", dirs.SnapDesktopFilesDir},
   149  	})
   150  	// foo file is still there
   151  	c.Assert(osutil.FileExists(mockDesktopFilePath), Equals, true)
   152  }
   153  
   154  func (s *desktopSuite) TestAddPackageDesktopFilesCleanup(c *C) {
   155  	mockDesktopFilePath := filepath.Join(dirs.SnapDesktopFilesDir, "foo_foobar1.desktop")
   156  	c.Assert(osutil.FileExists(mockDesktopFilePath), Equals, false)
   157  
   158  	err := os.MkdirAll(dirs.SnapDesktopFilesDir, 0755)
   159  	c.Assert(err, IsNil)
   160  
   161  	mockDesktopInstanceFilePath := filepath.Join(dirs.SnapDesktopFilesDir, "foo_instance_foobar.desktop")
   162  	err = ioutil.WriteFile(mockDesktopInstanceFilePath, mockDesktopFile, 0644)
   163  	c.Assert(err, IsNil)
   164  
   165  	err = os.MkdirAll(filepath.Join(dirs.SnapDesktopFilesDir, "foo_foobar2.desktop", "potato"), 0755)
   166  	c.Assert(err, IsNil)
   167  
   168  	info := snaptest.MockSnap(c, desktopAppYaml, &snap.SideInfo{Revision: snap.R(11)})
   169  
   170  	// generate .desktop file in the package baseDir
   171  	baseDir := info.MountDir()
   172  	err = os.MkdirAll(filepath.Join(baseDir, "meta", "gui"), 0755)
   173  	c.Assert(err, IsNil)
   174  
   175  	err = ioutil.WriteFile(filepath.Join(baseDir, "meta", "gui", "foobar1.desktop"), mockDesktopFile, 0644)
   176  	c.Assert(err, IsNil)
   177  	err = ioutil.WriteFile(filepath.Join(baseDir, "meta", "gui", "foobar2.desktop"), mockDesktopFile, 0644)
   178  	c.Assert(err, IsNil)
   179  
   180  	err = wrappers.AddSnapDesktopFiles(info)
   181  	c.Check(err, NotNil)
   182  	c.Check(osutil.FileExists(mockDesktopFilePath), Equals, false)
   183  	c.Check(s.mockUpdateDesktopDatabase.Calls(), HasLen, 0)
   184  	// foo_instance file was not removed by cleanup
   185  	c.Check(osutil.FileExists(mockDesktopInstanceFilePath), Equals, true)
   186  }
   187  
   188  // sanitize
   189  
   190  type sanitizeDesktopFileSuite struct {
   191  	testutil.BaseTest
   192  }
   193  
   194  var _ = Suite(&sanitizeDesktopFileSuite{})
   195  
   196  func (s *sanitizeDesktopFileSuite) SetUpTest(c *C) {
   197  	s.BaseTest.SetUpTest(c)
   198  	s.BaseTest.AddCleanup(snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {}))
   199  }
   200  
   201  func (s *sanitizeDesktopFileSuite) TearDownTest(c *C) {
   202  	s.BaseTest.TearDownTest(c)
   203  }
   204  
   205  func (s *sanitizeDesktopFileSuite) TestSanitizeIgnoreNotWhitelisted(c *C) {
   206  	snap := &snap.Info{SideInfo: snap.SideInfo{RealName: "foo", Revision: snap.R(12)}}
   207  	desktopContent := []byte(`[Desktop Entry]
   208  Name=foo
   209  UnknownKey=baz
   210  nonsense
   211  Icon=${SNAP}/meep
   212  
   213  # the empty line above is fine`)
   214  
   215  	e := wrappers.SanitizeDesktopFile(snap, "foo.desktop", desktopContent)
   216  	c.Assert(string(e), Equals, fmt.Sprintf(`[Desktop Entry]
   217  X-SnapInstanceName=foo
   218  Name=foo
   219  Icon=%s/foo/12/meep
   220  
   221  # the empty line above is fine
   222  `, dirs.SnapMountDir))
   223  }
   224  
   225  func (s *sanitizeDesktopFileSuite) TestSanitizeFiltersExec(c *C) {
   226  	snap, err := snap.InfoFromSnapYaml([]byte(`
   227  name: snap
   228  version: 1.0
   229  apps:
   230   app:
   231    command: cmd
   232  `))
   233  	c.Assert(err, IsNil)
   234  	desktopContent := []byte(`[Desktop Entry]
   235  Name=foo
   236  Exec=baz
   237  `)
   238  
   239  	e := wrappers.SanitizeDesktopFile(snap, "foo.desktop", desktopContent)
   240  	c.Assert(string(e), Equals, `[Desktop Entry]
   241  X-SnapInstanceName=snap
   242  Name=foo
   243  `)
   244  }
   245  
   246  func (s *sanitizeDesktopFileSuite) TestSanitizeFiltersExecPrefix(c *C) {
   247  	snap, err := snap.InfoFromSnapYaml([]byte(`
   248  name: snap
   249  version: 1.0
   250  apps:
   251   app:
   252    command: cmd
   253  `))
   254  	c.Assert(err, IsNil)
   255  	desktopContent := []byte(`[Desktop Entry]
   256  X-SnapInstanceName=snap
   257  Name=foo
   258  Exec=snap.app.evil.evil
   259  `)
   260  
   261  	e := wrappers.SanitizeDesktopFile(snap, "foo.desktop", desktopContent)
   262  	c.Assert(string(e), Equals, `[Desktop Entry]
   263  X-SnapInstanceName=snap
   264  Name=foo
   265  `)
   266  }
   267  
   268  func (s *sanitizeDesktopFileSuite) TestSanitizeFiltersExecRewriteFromDesktop(c *C) {
   269  	snap, err := snap.InfoFromSnapYaml([]byte(`
   270  name: snap
   271  version: 1.0
   272  apps:
   273   app:
   274    command: cmd
   275  `))
   276  	c.Assert(err, IsNil)
   277  	desktopContent := []byte(`[Desktop Entry]
   278  X-SnapInstanceName=snap
   279  Name=foo
   280  Exec=snap.app.evil.evil
   281  `)
   282  
   283  	e := wrappers.SanitizeDesktopFile(snap, "app.desktop", desktopContent)
   284  	c.Assert(string(e), Equals, fmt.Sprintf(`[Desktop Entry]
   285  X-SnapInstanceName=snap
   286  Name=foo
   287  Exec=env BAMF_DESKTOP_FILE_HINT=app.desktop %s/bin/snap.app
   288  `, dirs.SnapMountDir))
   289  }
   290  
   291  func (s *sanitizeDesktopFileSuite) TestSanitizeFiltersExecOk(c *C) {
   292  	snap, err := snap.InfoFromSnapYaml([]byte(`
   293  name: snap
   294  version: 1.0
   295  apps:
   296   app:
   297    command: cmd
   298  `))
   299  	c.Assert(err, IsNil)
   300  	desktopContent := []byte(`[Desktop Entry]
   301  Name=foo
   302  Exec=snap.app %U
   303  `)
   304  
   305  	e := wrappers.SanitizeDesktopFile(snap, "foo.desktop", desktopContent)
   306  	c.Assert(string(e), Equals, fmt.Sprintf(`[Desktop Entry]
   307  X-SnapInstanceName=snap
   308  Name=foo
   309  Exec=env BAMF_DESKTOP_FILE_HINT=foo.desktop %s/bin/snap.app %%U
   310  `, dirs.SnapMountDir))
   311  }
   312  
   313  // we do not support TryExec (even if its a valid line), this test ensures
   314  // we do not accidentally enable it
   315  func (s *sanitizeDesktopFileSuite) TestSanitizeFiltersTryExecIgnored(c *C) {
   316  	snap, err := snap.InfoFromSnapYaml([]byte(`
   317  name: snap
   318  version: 1.0
   319  apps:
   320   app:
   321    command: cmd
   322  `))
   323  	c.Assert(err, IsNil)
   324  	desktopContent := []byte(`[Desktop Entry]
   325  Name=foo
   326  TryExec=snap.app %U
   327  `)
   328  
   329  	e := wrappers.SanitizeDesktopFile(snap, "foo.desktop", desktopContent)
   330  	c.Assert(string(e), Equals, `[Desktop Entry]
   331  X-SnapInstanceName=snap
   332  Name=foo
   333  `)
   334  }
   335  
   336  func (s *sanitizeDesktopFileSuite) TestSanitizeWorthWithI18n(c *C) {
   337  	snap := &snap.Info{SideInfo: snap.SideInfo{RealName: "snap"}}
   338  	desktopContent := []byte(`[Desktop Entry]
   339  Name=foo
   340  GenericName=bar
   341  GenericName[de]=einsehrlangeszusammengesetzteswort
   342  GenericName[tlh_TLH]=Qapla'
   343  GenericName[ca@valencia]=Hola!
   344  Invalid=key
   345  Invalid[i18n]=key
   346  `)
   347  
   348  	e := wrappers.SanitizeDesktopFile(snap, "foo.desktop", desktopContent)
   349  	c.Assert(string(e), Equals, `[Desktop Entry]
   350  X-SnapInstanceName=snap
   351  Name=foo
   352  GenericName=bar
   353  GenericName[de]=einsehrlangeszusammengesetzteswort
   354  GenericName[tlh_TLH]=Qapla'
   355  GenericName[ca@valencia]=Hola!
   356  `)
   357  }
   358  
   359  func (s *sanitizeDesktopFileSuite) TestSanitizeDesktopActionsOk(c *C) {
   360  	snap := &snap.Info{}
   361  	desktopContent := []byte("[Desktop Action is-ok]\n")
   362  
   363  	e := wrappers.SanitizeDesktopFile(snap, "foo.desktop", desktopContent)
   364  	c.Assert(string(e), Equals, string(desktopContent))
   365  }
   366  
   367  func (s *sanitizeDesktopFileSuite) TestSanitizeDesktopFileAyatana(c *C) {
   368  	snap := &snap.Info{SideInfo: snap.SideInfo{RealName: "snap"}}
   369  
   370  	desktopContent := []byte(`[Desktop Entry]
   371  X-SnapInstanceName=snap
   372  Version=1.0
   373  Name=Firefox Web Browser
   374  X-Ayatana-Desktop-Shortcuts=NewWindow;Private
   375  
   376  [NewWindow Shortcut Group]
   377  Name=Open a New Window
   378  TargetEnvironment=Unity
   379  
   380  [Private Shortcut Group]
   381  Name=Private Mode
   382  TargetEnvironment=Unity
   383  `)
   384  
   385  	e := wrappers.SanitizeDesktopFile(snap, "foo.desktop", desktopContent)
   386  	c.Assert(string(e), Equals, string(desktopContent))
   387  }
   388  
   389  func (s *sanitizeDesktopFileSuite) TestSanitizeParallelInstancesPlain(c *C) {
   390  	snap, err := snap.InfoFromSnapYaml([]byte(`
   391  name: snap
   392  version: 1.0
   393  apps:
   394   app:
   395    command: cmd
   396  `))
   397  	snap.InstanceKey = "bar"
   398  	c.Assert(err, IsNil)
   399  	desktopContent := []byte(`[Desktop Entry]
   400  Name=foo
   401  Exec=snap.app
   402  `)
   403  	df := filepath.Base(snap.Apps["app"].DesktopFile())
   404  	e := wrappers.SanitizeDesktopFile(snap, df, desktopContent)
   405  	c.Assert(string(e), Equals, fmt.Sprintf(`[Desktop Entry]
   406  X-SnapInstanceName=snap_bar
   407  Name=foo
   408  Exec=env BAMF_DESKTOP_FILE_HINT=snap_bar_app.desktop %s/bin/snap_bar.app
   409  `, dirs.SnapMountDir))
   410  }
   411  
   412  func (s *sanitizeDesktopFileSuite) TestSanitizeParallelInstancesWithArgs(c *C) {
   413  	snap, err := snap.InfoFromSnapYaml([]byte(`
   414  name: snap
   415  version: 1.0
   416  apps:
   417   app:
   418    command: cmd
   419  `))
   420  	snap.InstanceKey = "bar"
   421  	c.Assert(err, IsNil)
   422  	desktopContent := []byte(`[Desktop Entry]
   423  Name=foo
   424  Exec=snap.app %U
   425  `)
   426  
   427  	df := filepath.Base(snap.Apps["app"].DesktopFile())
   428  	e := wrappers.SanitizeDesktopFile(snap, df, desktopContent)
   429  	c.Assert(string(e), Equals, fmt.Sprintf(`[Desktop Entry]
   430  X-SnapInstanceName=snap_bar
   431  Name=foo
   432  Exec=env BAMF_DESKTOP_FILE_HINT=snap_bar_app.desktop %s/bin/snap_bar.app %%U
   433  `, dirs.SnapMountDir))
   434  }
   435  
   436  func (s *sanitizeDesktopFileSuite) TestRewriteExecLineInvalid(c *C) {
   437  	snap := &snap.Info{}
   438  	_, err := wrappers.RewriteExecLine(snap, "foo.desktop", "Exec=invalid")
   439  	c.Assert(err, ErrorMatches, `invalid exec command: "invalid"`)
   440  }
   441  
   442  func (s *sanitizeDesktopFileSuite) TestRewriteExecLineOk(c *C) {
   443  	snap, err := snap.InfoFromSnapYaml([]byte(`
   444  name: snap
   445  version: 1.0
   446  apps:
   447   app:
   448    command: cmd
   449  `))
   450  	c.Assert(err, IsNil)
   451  
   452  	newl, err := wrappers.RewriteExecLine(snap, "foo.desktop", "Exec=snap.app")
   453  	c.Assert(err, IsNil)
   454  	c.Assert(newl, Equals, fmt.Sprintf("Exec=env BAMF_DESKTOP_FILE_HINT=foo.desktop %s/bin/snap.app", dirs.SnapMountDir))
   455  }
   456  
   457  func (s *sanitizeDesktopFileSuite) TestLangLang(c *C) {
   458  	langs := []struct {
   459  		line    string
   460  		isValid bool
   461  	}{
   462  		// langCodes
   463  		{"Name[lang]=lang-alone", true},
   464  		{"Name[_COUNTRY]=country-alone", false},
   465  		{"Name[.ENC-0DING]=encoding-alone", false},
   466  		{"Name[@modifier]=modifier-alone", false},
   467  		{"Name[lang_COUNTRY]=lang+country", true},
   468  		{"Name[lang.ENC-0DING]=lang+encoding", true},
   469  		{"Name[lang@modifier]=lang+modifier", true},
   470  		// could also test all bad combos of 2, and all combos of 3...
   471  		{"Name[lang_COUNTRY.ENC-0DING@modifier]=all", true},
   472  		// other localised entries
   473  		{"GenericName[xx]=a", true},
   474  		{"Comment[xx]=b", true},
   475  		{"Keywords[xx]=b", true},
   476  		// bad ones
   477  		{"Name[foo=bar", false},
   478  		{"Icon[xx]=bar", false},
   479  	}
   480  	for _, t := range langs {
   481  		c.Assert(wrappers.IsValidDesktopFileLine([]byte(t.line)), Equals, t.isValid)
   482  	}
   483  }
   484  
   485  func (s *sanitizeDesktopFileSuite) TestRewriteIconLine(c *C) {
   486  	snap, err := snap.InfoFromSnapYaml([]byte(`
   487  name: snap
   488  version: 1.0
   489  `))
   490  	c.Assert(err, IsNil)
   491  
   492  	newl, err := wrappers.RewriteIconLine(snap, "Icon=${SNAP}/icon.png")
   493  	c.Check(err, IsNil)
   494  	c.Check(newl, Equals, "Icon=${SNAP}/icon.png")
   495  
   496  	newl, err = wrappers.RewriteIconLine(snap, "Icon=snap.snap.icon")
   497  	c.Check(err, IsNil)
   498  	c.Check(newl, Equals, "Icon=snap.snap.icon")
   499  
   500  	newl, err = wrappers.RewriteIconLine(snap, "Icon=other-icon")
   501  	c.Check(err, IsNil)
   502  	c.Check(newl, Equals, "Icon=other-icon")
   503  
   504  	snap.InstanceKey = "bar"
   505  	newl, err = wrappers.RewriteIconLine(snap, "Icon=snap.snap.icon")
   506  	c.Check(err, IsNil)
   507  	c.Check(newl, Equals, "Icon=snap.snap_bar.icon")
   508  
   509  	_, err = wrappers.RewriteIconLine(snap, "Icon=snap.othersnap.icon")
   510  	c.Check(err, ErrorMatches, `invalid icon name: "snap.othersnap.icon", must start with "snap.snap."`)
   511  
   512  	_, err = wrappers.RewriteIconLine(snap, "Icon=/etc/passwd")
   513  	c.Check(err, ErrorMatches, `icon path "/etc/passwd" is not part of the snap`)
   514  
   515  	_, err = wrappers.RewriteIconLine(snap, "Icon=${SNAP}/./icon.png")
   516  	c.Check(err, ErrorMatches, `icon path "\${SNAP}/./icon.png" is not canonicalized, did you mean "\${SNAP}/icon.png"\?`)
   517  
   518  	_, err = wrappers.RewriteIconLine(snap, "Icon=${SNAP}/../outside/icon.png")
   519  	c.Check(err, ErrorMatches, `icon path "\${SNAP}/../outside/icon.png" is not canonicalized, did you mean "outside/icon.png"\?`)
   520  }
   521  
   522  func (s *sanitizeDesktopFileSuite) TestSanitizeParallelInstancesIconName(c *C) {
   523  	snap, err := snap.InfoFromSnapYaml([]byte(`
   524  name: snap
   525  version: 1.0
   526  apps:
   527   app:
   528    command: cmd
   529  `))
   530  	snap.InstanceKey = "bar"
   531  	c.Assert(err, IsNil)
   532  	desktopContent := []byte(`[Desktop Entry]
   533  Name=foo
   534  Icon=snap.snap.icon
   535  Exec=snap.app
   536  `)
   537  	df := filepath.Base(snap.Apps["app"].DesktopFile())
   538  	e := wrappers.SanitizeDesktopFile(snap, df, desktopContent)
   539  	c.Assert(string(e), Equals, fmt.Sprintf(`[Desktop Entry]
   540  X-SnapInstanceName=snap_bar
   541  Name=foo
   542  Icon=snap.snap_bar.icon
   543  Exec=env BAMF_DESKTOP_FILE_HINT=snap_bar_app.desktop %s/bin/snap_bar.app
   544  `, dirs.SnapMountDir))
   545  }
   546  
   547  func (s *desktopSuite) TestAddRemoveDesktopFiles(c *C) {
   548  	var tests = []struct {
   549  		instance                string
   550  		upstreamDesktopFileName string
   551  
   552  		expectedDesktopFileName string
   553  	}{
   554  		// normal cases
   555  		{"", "upstream.desktop", "foo_upstream.desktop"},
   556  		{"instance", "upstream.desktop", "foo+instance_upstream.desktop"},
   557  		// pathological cases are handled
   558  		{"", "instance.desktop", "foo_instance.desktop"},
   559  		{"instance", "instance.desktop", "foo+instance_instance.desktop"},
   560  	}
   561  
   562  	for _, t := range tests {
   563  		expectedDesktopFilePath := filepath.Join(dirs.SnapDesktopFilesDir, t.expectedDesktopFileName)
   564  		c.Assert(osutil.FileExists(expectedDesktopFilePath), Equals, false)
   565  
   566  		info := snaptest.MockSnap(c, desktopAppYaml, &snap.SideInfo{Revision: snap.R(11)})
   567  		info.InstanceKey = t.instance
   568  
   569  		// generate .desktop file in the package baseDir
   570  		baseDir := info.MountDir()
   571  		err := os.MkdirAll(filepath.Join(baseDir, "meta", "gui"), 0755)
   572  		c.Assert(err, IsNil)
   573  
   574  		err = ioutil.WriteFile(filepath.Join(baseDir, "meta", "gui", t.upstreamDesktopFileName), mockDesktopFile, 0644)
   575  		c.Assert(err, IsNil)
   576  
   577  		err = wrappers.AddSnapDesktopFiles(info)
   578  		c.Assert(err, IsNil)
   579  		c.Assert(osutil.FileExists(expectedDesktopFilePath), Equals, true)
   580  
   581  		// remove it again
   582  		err = wrappers.RemoveSnapDesktopFiles(info)
   583  		c.Assert(err, IsNil)
   584  		c.Assert(osutil.FileExists(expectedDesktopFilePath), Equals, false)
   585  	}
   586  }