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 }