github.com/jacekolszak/noteo@v0.5.0/repository/repository_test.go (about)

     1  package repository_test
     2  
     3  import (
     4  	"context"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/jacekolszak/noteo/note"
    12  	"github.com/jacekolszak/noteo/repository"
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  func TestRepository_Add(t *testing.T) {
    18  	t.Run("should generate name", func(t *testing.T) {
    19  		tests := map[string]struct {
    20  			content          string
    21  			expectedFilename string
    22  		}{
    23  			"note with YAML front matter black": {
    24  				content: `---
    25  Tags: ""
    26  ---
    27  
    28  yaml`,
    29  				expectedFilename: "yaml.md",
    30  			},
    31  			"note with YAML without blank line:": {
    32  				content: `---
    33  Tags: ""
    34  ---
    35  yaml-without-blank-line`,
    36  				expectedFilename: "yaml-without-blank-line.md",
    37  			},
    38  			"should remove illegal chars": {
    39  				content:          "chars`~!@#$%^&*()_+[{]}\\|;:'\",<>/?",
    40  				expectedFilename: "chars.md",
    41  			},
    42  			"should replace diacritics with ascii": {
    43  				content:          "ąćęłńóśżź",
    44  				expectedFilename: "acelnoszz.md",
    45  			},
    46  			"should replace space with dash": {
    47  				content:          "foo bar",
    48  				expectedFilename: "foo-bar.md",
    49  			},
    50  			"should trim spaces": {
    51  				content:          " trimspaces ",
    52  				expectedFilename: "trimspaces.md",
    53  			},
    54  			"should trim spaces after removing illegal chars": {
    55  				content:          "% removedchars @",
    56  				expectedFilename: "removedchars.md",
    57  			},
    58  			"should trim newlines": {
    59  				content:          "\nnewlines\n",
    60  				expectedFilename: "newlines.md",
    61  			},
    62  			"should lowercase": {
    63  				content:          "LOWERCASE",
    64  				expectedFilename: "lowercase.md",
    65  			},
    66  			"unknown": {
    67  				content:          " @#",
    68  				expectedFilename: "unknown.md",
    69  			},
    70  			"unknown with front matter": {
    71  				content: `---
    72  Tags: ""
    73  ---
    74  
    75  `,
    76  				expectedFilename: "unknown.md",
    77  			},
    78  			"yaml without break line": {
    79  				content: `---
    80  Tags: ""
    81  ---`,
    82  				expectedFilename: "unknown.md",
    83  			},
    84  			"should use only first line of body as filename": {
    85  				content: `---
    86  Tags: ""
    87  ---
    88  
    89  first
    90  second`,
    91  				expectedFilename: "first.md",
    92  			},
    93  			"should use capital letter word for very long text": {
    94  				content:          "Very long text and only This word will be used as title",
    95  				expectedFilename: "this.md",
    96  			},
    97  			"should trim very long text": {
    98  				content:          "this is very long text without any capital letter words",
    99  				expectedFilename: "this-is-very-long-text-without.md",
   100  			},
   101  			"should remove carriage return": {
   102  				content:          "return\r",
   103  				expectedFilename: "return.md",
   104  			},
   105  		}
   106  		for name, test := range tests {
   107  			t.Run(name, func(t *testing.T) {
   108  				_, repo := repo(t)
   109  				// when
   110  				file, err := repo.Add(test.content)
   111  				// then
   112  				require.NoError(t, err)
   113  				assert.Equal(t, test.expectedFilename, file)
   114  			})
   115  		}
   116  	})
   117  }
   118  
   119  func TestRepository_Move(t *testing.T) {
   120  	t.Run("should rename file", func(t *testing.T) {
   121  		dir, repo := repo(t)
   122  		require.NoError(t, os.Chdir(dir))
   123  		writeFile(t, filepath.Join("source.md"), "source")
   124  		linkFile := filepath.Join(dir, "link.md")
   125  		writeFile(t, linkFile, "[link](source.md)")
   126  		ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second)
   127  		defer cancelFunc()
   128  		// when
   129  		notes, success, errors := repo.Move(ctx, "source.md", "target.md")
   130  		// then
   131  		assertSuccess(t, ctx, notes, success, errors)
   132  		assert.NoFileExists(t, "source.md")
   133  		assert.FileExists(t, "target.md")
   134  		assertFileEquals(t, linkFile, "[link](target.md)")
   135  	})
   136  
   137  	t.Run("should move file to directory", func(t *testing.T) {
   138  		dir, repo := repo(t)
   139  		require.NoError(t, os.Chdir(dir))
   140  		require.NoError(t, os.MkdirAll("target", os.ModePerm))
   141  		writeFile(t, "source.md", "source")
   142  		linkFile := filepath.Join(dir, "link.md")
   143  		writeFile(t, linkFile, "[link](source.md)")
   144  		ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second)
   145  		defer cancelFunc()
   146  		// when
   147  		notes, success, errors := repo.Move(ctx, "source.md", "target")
   148  		// then
   149  		assertSuccess(t, ctx, notes, success, errors)
   150  		assert.NoFileExists(t, "source.md")
   151  		assert.FileExists(t, filepath.Join("target", "source.md"))
   152  		assertFileEquals(t, linkFile, "[link](target/source.md)")
   153  	})
   154  
   155  	t.Run("should move whole dir", func(t *testing.T) {
   156  		dir, repo := repo(t)
   157  		require.NoError(t, os.Chdir(dir))
   158  		require.NoError(t, os.MkdirAll("source", os.ModePerm))
   159  		require.NoError(t, os.MkdirAll("target", os.ModePerm))
   160  		sourceDir := filepath.Join(dir, "source")
   161  		sourceFile := filepath.Join(sourceDir, "foo.md")
   162  		writeFile(t, sourceFile, "foo")
   163  		linkFile := filepath.Join(dir, "link.md")
   164  		writeFile(t, linkFile, "[link](source/foo.md)")
   165  		ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second)
   166  		defer cancelFunc()
   167  		// when
   168  		notes, success, errors := repo.Move(ctx, "source", "target")
   169  		// then
   170  		assertSuccess(t, ctx, notes, success, errors)
   171  		assert.NoDirExists(t, sourceDir)
   172  		assert.DirExists(t, filepath.Join(dir, "target", "source"))
   173  		assert.FileExists(t, filepath.Join(dir, "target", "source", "foo.md"))
   174  		assertFileEquals(t, linkFile, "[link](target/source/foo.md)")
   175  	})
   176  }
   177  
   178  func assertSuccess(t *testing.T, ctx context.Context, notes <-chan *note.Note, success <-chan bool, errors <-chan error) {
   179  	var successClosed, errorClosed, notesClosed bool
   180  	for !successClosed || !errorClosed || !notesClosed {
   181  		select {
   182  		case _, ok := <-notes:
   183  			if !ok {
   184  				notesClosed = true
   185  				continue
   186  			}
   187  		case e, ok := <-errors:
   188  			if !ok {
   189  				errorClosed = true
   190  				continue
   191  			}
   192  			require.FailNowf(t, "error received", "%v", e)
   193  		case <-ctx.Done():
   194  			require.FailNow(t, "timeout")
   195  		case s, ok := <-success:
   196  			if !ok {
   197  				successClosed = true
   198  				continue
   199  			}
   200  			assert.True(t, s)
   201  		}
   202  	}
   203  }
   204  
   205  func assertFileEquals(t *testing.T, file, expected string) {
   206  	content, err := ioutil.ReadFile(file)
   207  	require.NoError(t, err)
   208  	assert.Equal(t, expected, string(content))
   209  }
   210  
   211  func repo(t *testing.T) (dir string, repo *repository.Repository) {
   212  	dir, err := ioutil.TempDir("", "noteo-test")
   213  	require.NoError(t, err)
   214  	_, err = repository.Init(dir)
   215  	require.NoError(t, err)
   216  	repo, err = repository.ForWorkDir(dir)
   217  	require.NoError(t, err)
   218  	return dir, repo
   219  }
   220  
   221  func writeFile(t *testing.T, filename, content string) {
   222  	require.NoError(t, ioutil.WriteFile(filename, []byte(content), os.ModePerm))
   223  }