github.com/ubuntu/ubuntu-report@v1.7.4-0.20240410144652-96f37d845fac/cmd/ubuntu-report/generate_test.go (about)

     1  package main
     2  
     3  import (
     4  	"bufio"
     5  	"flag"
     6  	"io"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/pkg/errors"
    14  	"github.com/spf13/cobra"
    15  	"github.com/spf13/cobra/doc"
    16  	"github.com/ubuntu/ubuntu-report/internal/helper"
    17  )
    18  
    19  /*
    20   * using test file for manpage and bash completion generate so that
    21   * we don't embed the code and dependencies in final binary
    22   */
    23  
    24  var generate = flag.Bool("generate", false, "generate manpages and completion files")
    25  var out = flag.String("path", "build", "custom directory where to generate files when using --generate")
    26  
    27  func TestGenerateManpage(t *testing.T) {
    28  	if !*generate {
    29  		helper.SkipIfShort(t)
    30  		t.Log("mocking man page generation, --generate isn't set")
    31  		_, tearDown := chTempDir(t)
    32  		defer tearDown()
    33  	} else {
    34  		t.Parallel()
    35  	}
    36  
    37  	if err := os.Mkdir(*out, 0755); err != nil && os.IsNotExist(err) {
    38  		t.Fatalf("couldn't create %s directory: %v", *out, err)
    39  	}
    40  	header := &doc.GenManHeader{
    41  		Title:   "Ubuntu Report",
    42  		Section: "3",
    43  	}
    44  	if err := doc.GenManTree(generateRootCmd(), header, *out); err != nil {
    45  		t.Fatalf("couldn't generate manpage: %v", err)
    46  	}
    47  }
    48  
    49  func TestGenerateCompletion(t *testing.T) {
    50  	if !*generate {
    51  		helper.SkipIfShort(t)
    52  		t.Log("mocking bash and zsh completion generation, --generate isn't set")
    53  		_, tearDown := chTempDir(t)
    54  		defer tearDown()
    55  	} else {
    56  		t.Parallel()
    57  	}
    58  
    59  	rootCmd := generateRootCmd()
    60  	if err := os.Mkdir(*out, 0755); err != nil && os.IsNotExist(err) {
    61  		t.Fatalf("couldn't create %s directory: %v", *out, err)
    62  	}
    63  	if err := rootCmd.GenBashCompletionFile(filepath.Join(*out, "bash-completion")); err != nil {
    64  		t.Fatalf("couldn't generate bash completion: %v", err)
    65  	}
    66  	if err := rootCmd.GenZshCompletionFile(filepath.Join(*out, "zsh-completion")); err != nil {
    67  		t.Fatalf("couldn't generate bazshsh completion: %v", err)
    68  	}
    69  }
    70  
    71  func TestGenerateREADME(t *testing.T) {
    72  	sp := filepath.Join("..", "..", "README.md")
    73  	if _, err := os.Stat(sp); err != nil && os.IsNotExist(err) {
    74  		t.Skip("no README.md file: doesn't run from source repository, nothing to update")
    75  	}
    76  	if !*generate {
    77  		helper.SkipIfShort(t)
    78  		t.Log("mock README generation, --generate isn't set")
    79  		sp = filepath.Join(curDir(t), sp)
    80  		d, tearDown := chTempDir(t)
    81  		defer tearDown()
    82  
    83  		newsp := filepath.Join(d, "README.md")
    84  		helper.CopyFile(t, sp, newsp)
    85  		sp = newsp
    86  	} else {
    87  		t.Parallel()
    88  	}
    89  
    90  	dp := sp + ".new"
    91  	src, err := os.Open(sp)
    92  	if err != nil {
    93  		t.Fatalf("couldn't open %s: %v", sp, err)
    94  	}
    95  	defer src.Close()
    96  	dst, err := os.Create(dp)
    97  	if err != nil {
    98  		t.Fatalf("couldn't create %s: %v", dp, err)
    99  	}
   100  	defer dst.Close()
   101  
   102  	// write start of README
   103  	scanner := bufio.NewScanner(src)
   104  	for scanner.Scan() {
   105  		txt := scanner.Text()
   106  		mustWrite(t, dst, txt)
   107  		if txt == "## Command line usage" {
   108  			mustWrite(t, dst, "")
   109  			break
   110  		}
   111  	}
   112  
   113  	// write generated command line
   114  	cmds := []*cobra.Command{generateRootCmd()}
   115  	cmds = append(cmds, cmds[0].Commands()...)
   116  	for _, cmd := range cmds {
   117  		pr, pw := io.Pipe()
   118  
   119  		go func() {
   120  			if err := doc.GenMarkdown(cmd, pw); err != nil {
   121  				pw.CloseWithError(errors.Wrapf(err, "generate markdown for %s failed", cmd.Name()))
   122  				return
   123  			}
   124  			pw.Close()
   125  		}()
   126  
   127  		mScanner := bufio.NewScanner(pr)
   128  		for mScanner.Scan() {
   129  			txt := mScanner.Text()
   130  			if strings.HasPrefix(txt, "### SEE ALSO") {
   131  				break
   132  			}
   133  			// interactive is an alias to ubuntu-report only, don't file up more info
   134  			if cmd.Name() == "interactive" && strings.HasPrefix(txt, "### Synopsis") {
   135  				break
   136  			}
   137  			// add a subindentation
   138  			if strings.HasPrefix(txt, "##") {
   139  				txt = "#" + txt
   140  			}
   141  			mustWrite(t, dst, txt)
   142  		}
   143  
   144  		if err = mScanner.Err(); err != nil {
   145  			t.Fatalf("error while reading generated markdown for %s: %v", cmd.Name(), err)
   146  		}
   147  	}
   148  
   149  	// skip to next paragraph (ignore previous generation) and write to the end of file
   150  	skip := true
   151  	for scanner.Scan() {
   152  		txt := scanner.Text()
   153  		if skip && strings.HasPrefix(txt, "## ") {
   154  			skip = false
   155  		}
   156  		if !skip {
   157  			mustWrite(t, dst, txt)
   158  		}
   159  	}
   160  	if err = scanner.Err(); err != nil {
   161  		t.Fatalf("error while reading %s: %v", sp, err)
   162  	}
   163  
   164  	dst.Close()
   165  	if err = os.Rename(dp, sp); err != nil {
   166  		t.Fatalf("couldn't rename %s to %s: %v", dp, sp, err)
   167  	}
   168  }
   169  
   170  func mustWrite(t *testing.T, f *os.File, s string) {
   171  	if _, err := f.WriteString(s + "\n"); err != nil {
   172  		t.Fatalf("couldn't write '%s' to %s: %v", s, f.Name(), err)
   173  	}
   174  }
   175  
   176  func curDir(t *testing.T) string {
   177  	t.Helper()
   178  
   179  	c, err := os.Getwd()
   180  	if err != nil {
   181  		t.Fatal("couldn't get current directory", err)
   182  	}
   183  	return c
   184  }
   185  
   186  func chTempDir(t *testing.T) (string, func()) {
   187  	t.Helper()
   188  	d, err := ioutil.TempDir("", "ubuntu-report-tests")
   189  	if err != nil {
   190  		t.Fatal("couldn't create temporary directory", err)
   191  	}
   192  	c := curDir(t)
   193  	if err = os.Chdir(d); err != nil {
   194  		t.Fatalf("couldn't change directory to %s: %v", d, err)
   195  	}
   196  
   197  	return d, func() {
   198  		if err = os.Chdir(c); err != nil {
   199  			t.Fatalf("couldn't restore to initial directory %s, %v", c, err)
   200  		}
   201  		if err = os.RemoveAll(d); err != nil {
   202  			t.Fatalf("couldn't clean temporary directory %s, %v", d, err)
   203  		}
   204  	}
   205  }