github.com/jacekolszak/noteo@v0.5.0/note/note_test.go (about)

     1  package note_test
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/jacekolszak/noteo/date"
    12  	"github.com/jacekolszak/noteo/note"
    13  	"github.com/jacekolszak/noteo/tag"
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  func TestNew(t *testing.T) {
    19  	t.Run("should return note for missing file", func(t *testing.T) {
    20  		assert.NotNil(t, note.New("missing"))
    21  	})
    22  }
    23  
    24  func TestNewWithModified(t *testing.T) {
    25  	t.Run("should return note for missing file", func(t *testing.T) {
    26  		assert.NotNil(t, note.NewWithModified("missing", time.Now()))
    27  	})
    28  }
    29  
    30  func TestNote_Path(t *testing.T) {
    31  	t.Run("should return path", func(t *testing.T) {
    32  		n := note.New("path")
    33  		// expect
    34  		assert.Equal(t, "path", n.Path())
    35  	})
    36  }
    37  
    38  func TestNote_Modified(t *testing.T) {
    39  	t.Run("should return error for missing file", func(t *testing.T) {
    40  		n := note.New("missing")
    41  		// when
    42  		_, err := n.Modified()
    43  		// then
    44  		assert.Error(t, err)
    45  	})
    46  
    47  	t.Run("should not error for existing file", func(t *testing.T) {
    48  		file, err := ioutil.TempFile("", "noteo-test")
    49  		require.NoError(t, err)
    50  		n := note.New(file.Name())
    51  		// when
    52  		_, err = n.Modified()
    53  		// then
    54  		assert.NoError(t, err)
    55  	})
    56  
    57  	t.Run("should return passed modified time", func(t *testing.T) {
    58  		givenTime, err := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
    59  		require.NoError(t, err)
    60  		n := note.NewWithModified("path", givenTime)
    61  		// when
    62  		modified, err := n.Modified()
    63  		// then
    64  		require.NoError(t, err)
    65  		assert.Equal(t, givenTime, modified)
    66  	})
    67  }
    68  
    69  func TestNote_Created(t *testing.T) {
    70  	t.Run("should return zero value Time (1 Jan 1970) for note without Created tag", func(t *testing.T) {
    71  		filename := writeTempFile(t, "body")
    72  		n := note.New(filename)
    73  		// when
    74  		created, err := n.Created()
    75  		// then
    76  		require.NoError(t, err)
    77  		assert.Equal(t, time.Time{}, created)
    78  	})
    79  
    80  	t.Run("should return time from Created tag", func(t *testing.T) {
    81  		filename := writeTempFile(t, "---\nCreated: 2006-01-02\n---\nbody")
    82  		n := note.New(filename)
    83  		// when
    84  		created, err := n.Created()
    85  		// then
    86  		require.NoError(t, err)
    87  		expectedTime, err := date.Parse("2006-01-02")
    88  		require.NoError(t, err)
    89  		assert.Equal(t, expectedTime, created)
    90  	})
    91  }
    92  
    93  func TestNote_Tags(t *testing.T) {
    94  	t.Run("should return tags", func(t *testing.T) {
    95  		tests := map[string]struct {
    96  			content      string
    97  			expectedTags []string
    98  		}{
    99  			"no tags": {
   100  				content: "",
   101  			},
   102  			"empty tags": {
   103  				content: "---\nTags: \n---",
   104  			},
   105  			"one tag": {
   106  				content:      "---\nTags: tag\n---",
   107  				expectedTags: []string{"tag"},
   108  			},
   109  			"space separated": {
   110  				content:      "---\nTags: tag1 tag2\n---",
   111  				expectedTags: []string{"tag1", "tag2"},
   112  			},
   113  			"comma separated": {
   114  				content:      "---\nTags: tag1,tag2\n---",
   115  				expectedTags: []string{"tag1", "tag2"},
   116  			},
   117  			"list": {
   118  				content:      "---\nTags: [tag1, tag2]\n---",
   119  				expectedTags: []string{"tag1", "tag2"},
   120  			},
   121  			"tag with space in the beginning": {
   122  				content:      "---\nTags: [\" tag\"]\n---",
   123  				expectedTags: []string{"tag"},
   124  			},
   125  			"tag with space on the end": {
   126  				content:      "---\nTags: [\"tag \"]\n---",
   127  				expectedTags: []string{"tag"},
   128  			},
   129  		}
   130  		for name, test := range tests {
   131  			t.Run(name, func(t *testing.T) {
   132  				filename := writeTempFile(t, test.content)
   133  				n := note.New(filename)
   134  				// expect
   135  				assertTags(t, n, test.expectedTags...)
   136  			})
   137  		}
   138  	})
   139  }
   140  
   141  func TestNote_SetTag(t *testing.T) {
   142  	t.Run("should add tag for file without front matter", func(t *testing.T) {
   143  		filename := writeTempFile(t, "text")
   144  		n := note.New(filename)
   145  		newTag, err := tag.New("tag")
   146  		require.NoError(t, err)
   147  		// when
   148  		err = n.SetTag(newTag)
   149  		// then
   150  		require.NoError(t, err)
   151  		assertTags(t, n, "tag")
   152  	})
   153  
   154  	t.Run("should set tag with relative date", func(t *testing.T) {
   155  		date.SetNow(func() time.Time {
   156  			return time.Date(2020, 9, 10, 16, 30, 11, 0, time.FixedZone("CEST", 60*60*2))
   157  		})
   158  		defer date.SetNow(time.Now)
   159  		filename := writeTempFile(t, "")
   160  		n := note.New(filename)
   161  		// when
   162  		err := n.SetTag(newTag(t, "deadline:now"))
   163  		// then
   164  		require.NoError(t, err)
   165  		assertTags(t, n, "deadline:2020-09-10T16:30:11+02:00")
   166  	})
   167  
   168  	t.Run("should update existing tag", func(t *testing.T) {
   169  		filename := writeTempFile(t, "---\nTags: tag:1\n---\nbody")
   170  		n := note.New(filename)
   171  		newTag, err := tag.New("tag:2")
   172  		require.NoError(t, err)
   173  		// when
   174  		err = n.SetTag(newTag)
   175  		// then
   176  		require.NoError(t, err)
   177  		assertTags(t, n, "tag:2")
   178  	})
   179  }
   180  
   181  func TestNote_RemoveTag(t *testing.T) {
   182  	t.Run("should remove tag", func(t *testing.T) {
   183  		filename := writeTempFile(t, "---\nTags: tag another\n---\ntext")
   184  		n := note.New(filename)
   185  		tagToRemove := newTag(t, "tag")
   186  		// when
   187  		err := n.RemoveTag(tagToRemove)
   188  		// then
   189  		require.NoError(t, err)
   190  		assertTags(t, n, "another")
   191  	})
   192  
   193  	t.Run("should remove last remaining tag", func(t *testing.T) {
   194  		filename := writeTempFile(t, "---\nTags: tag\n---\ntext")
   195  		n := note.New(filename)
   196  		tagToRemove := newTag(t, "tag")
   197  		// when
   198  		err := n.RemoveTag(tagToRemove)
   199  		// then
   200  		require.NoError(t, err)
   201  		assertNoTags(t, n)
   202  	})
   203  
   204  	t.Run("removing missing tag does nothing", func(t *testing.T) {
   205  		filename := writeTempFile(t, "content")
   206  		n := note.New(filename)
   207  		missingTag := newTag(t, "missing")
   208  		// when
   209  		err := n.RemoveTag(missingTag)
   210  		// then
   211  		require.NoError(t, err)
   212  		assertNoTags(t, n)
   213  	})
   214  }
   215  
   216  func TestNote_Save(t *testing.T) {
   217  	t.Run("should add yaml front matter for file without it", func(t *testing.T) {
   218  		filename := writeTempFile(t, "text")
   219  		n := note.New(filename)
   220  		require.NoError(t, n.SetTag(newTag(t, "tag")))
   221  		// when
   222  		saved, err := n.Save()
   223  		// then
   224  		require.NoError(t, err)
   225  		assert.True(t, saved)
   226  		// and
   227  		assertFileEquals(t, filename, "---\nTags: tag\n---\ntext")
   228  	})
   229  
   230  	t.Run("should update front matter", func(t *testing.T) {
   231  		filename := writeTempFile(t, "---\nTags: foo\n---\n\ntext")
   232  		n := note.New(filename)
   233  		require.NoError(t, n.SetTag(newTag(t, "tag")))
   234  		// when
   235  		saved, err := n.Save()
   236  		// then
   237  		require.NoError(t, err)
   238  		assert.True(t, saved)
   239  		// and
   240  		assertFileEquals(t, filename, "---\nTags: foo tag\n---\n\ntext")
   241  	})
   242  
   243  	t.Run("should not save file if nothing changed", func(t *testing.T) {
   244  		filename := writeTempFile(t, "text")
   245  		n := note.New(filename)
   246  		// when
   247  		saved, err := n.Save()
   248  		// then
   249  		assert.False(t, saved)
   250  		assert.NoError(t, err)
   251  	})
   252  }
   253  
   254  func TestNote_Body(t *testing.T) {
   255  	t.Run("should return body when note does not have a front matter", func(t *testing.T) {
   256  		filename := writeTempFile(t, "body")
   257  		n := note.New(filename)
   258  		// when
   259  		actual, err := n.Body()
   260  		// then
   261  		require.NoError(t, err)
   262  		assert.Equal(t, "body", actual)
   263  	})
   264  
   265  	t.Run("should return body when note has a front matter", func(t *testing.T) {
   266  		filename := writeTempFile(t, "---\nTags: tag\n---\nbody")
   267  		n := note.New(filename)
   268  		// when
   269  		actual, err := n.Body()
   270  		// then
   271  		require.NoError(t, err)
   272  		assert.Equal(t, "body", actual)
   273  	})
   274  
   275  	t.Run("should return empty body", func(t *testing.T) {
   276  		filename := writeTempFile(t, "---\nTags: tag\n---\n")
   277  		n := note.New(filename)
   278  		// when
   279  		actual, err := n.Body()
   280  		// then
   281  		require.NoError(t, err)
   282  		assert.Empty(t, actual)
   283  	})
   284  }
   285  
   286  func TestNote_UpdateLink(t *testing.T) {
   287  	t.Run("should not change the body if link is missing", func(t *testing.T) {
   288  		filename := writeTempFile(t, "body")
   289  		n := note.New(filename)
   290  		// when
   291  		err := n.UpdateLink("from", "to")
   292  		require.NoError(t, err)
   293  		// then
   294  		body, err := n.Body()
   295  		require.NoError(t, err)
   296  		assert.Equal(t, "body", body)
   297  	})
   298  
   299  	tests := []func(string) string{
   300  		func(filename string) string {
   301  			return "from.md"
   302  		},
   303  		func(filename string) string {
   304  			return filepath.Join(filepath.Dir(filename), "from.md")
   305  		},
   306  		func(filename string) string {
   307  			return filepath.Join("..", filepath.Base(filepath.Dir(filename)), "from.md")
   308  		},
   309  	}
   310  
   311  	t.Run("should update markdown link when from parameter is", func(t *testing.T) {
   312  		for _, from := range tests {
   313  			filename := writeTempFile(t, "[link](from.md)")
   314  			n := note.New(filename)
   315  			t.Run(from(filename), func(t *testing.T) {
   316  				// when
   317  				err := n.UpdateLink(from(filename), "to.md")
   318  				require.NoError(t, err)
   319  				// then
   320  				body, err := n.Body()
   321  				require.NoError(t, err)
   322  				assert.Equal(t, "[link](to.md)", body)
   323  			})
   324  		}
   325  	})
   326  
   327  	t.Run("should update markdown link when link path is", func(t *testing.T) {
   328  		for _, linkPath := range tests {
   329  			filename := writeTempFileWithFunction(t, func(filename string) string {
   330  				return fmt.Sprintf("[link](%s)", linkPath(filename))
   331  			})
   332  			n := note.New(filename)
   333  			t.Run(linkPath(filename), func(t *testing.T) {
   334  				// when
   335  				err := n.UpdateLink("from.md", "to.md")
   336  				require.NoError(t, err)
   337  				// then
   338  				body, err := n.Body()
   339  				require.NoError(t, err)
   340  				assert.Equal(t, "[link](to.md)", body)
   341  			})
   342  		}
   343  	})
   344  
   345  	t.Run("should update markdown link when directory is renamed", func(t *testing.T) {
   346  		filename := writeTempFile(t, "[link](source/file.md)")
   347  		n := note.New(filename)
   348  		// when
   349  		err := n.UpdateLink("source", "target")
   350  		require.NoError(t, err)
   351  		// then
   352  		body, err := n.Body()
   353  		require.NoError(t, err)
   354  		assert.Equal(t, "[link](target/file.md)", body)
   355  	})
   356  
   357  	t.Run("should not update markdown link", func(t *testing.T) {
   358  		filename := writeTempFile(t, "[link](other.md)")
   359  		n := note.New(filename)
   360  		// when
   361  		err := n.UpdateLink("from.md", "to.md")
   362  		require.NoError(t, err)
   363  		// then
   364  		body, err := n.Body()
   365  		require.NoError(t, err)
   366  		assert.Equal(t, "[link](other.md)", body)
   367  	})
   368  
   369  }
   370  
   371  func writeTempFile(t *testing.T, content string) string {
   372  	file, err := ioutil.TempFile("", "noteo-test")
   373  	require.NoError(t, err)
   374  	require.NoError(t, ioutil.WriteFile(file.Name(), []byte(content), os.ModePerm))
   375  	return file.Name()
   376  }
   377  
   378  func writeTempFileWithFunction(t *testing.T, content func(filename string) string) string {
   379  	file, err := ioutil.TempFile("", "noteo-test")
   380  	require.NoError(t, err)
   381  	require.NoError(t, ioutil.WriteFile(file.Name(), []byte(content(file.Name())), os.ModePerm))
   382  	return file.Name()
   383  }
   384  
   385  func assertFileEquals(t *testing.T, filename, expectedContent string) {
   386  	bytes, err := ioutil.ReadFile(filename)
   387  	require.NoError(t, err)
   388  	assert.Equal(t, expectedContent, string(bytes))
   389  }
   390  
   391  func assertNoTags(t *testing.T, n *note.Note) {
   392  	assertTags(t, n)
   393  }
   394  
   395  func assertTags(t *testing.T, n *note.Note, expectedTags ...string) {
   396  	tags, err := n.Tags()
   397  	require.NoError(t, err)
   398  	require.Equal(t, len(expectedTags), len(tags), "different tags len")
   399  	for i, expectedTag := range expectedTags {
   400  		assert.Equal(t, newTag(t, expectedTag), tags[i])
   401  	}
   402  }
   403  
   404  func newTag(t *testing.T, name string) tag.Tag {
   405  	createdTag, err := tag.New(name)
   406  	require.NoError(t, err)
   407  	return createdTag
   408  }