github.com/olljanat/moby@v1.13.1/builder/dockerfile/parser/parser_test.go (about)

     1  package parser
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"runtime"
    10  	"testing"
    11  )
    12  
    13  const testDir = "testfiles"
    14  const negativeTestDir = "testfiles-negative"
    15  const testFileLineInfo = "testfile-line/Dockerfile"
    16  
    17  func getDirs(t *testing.T, dir string) []string {
    18  	f, err := os.Open(dir)
    19  	if err != nil {
    20  		t.Fatal(err)
    21  	}
    22  
    23  	defer f.Close()
    24  
    25  	dirs, err := f.Readdirnames(0)
    26  	if err != nil {
    27  		t.Fatal(err)
    28  	}
    29  
    30  	return dirs
    31  }
    32  
    33  func TestTestNegative(t *testing.T) {
    34  	for _, dir := range getDirs(t, negativeTestDir) {
    35  		dockerfile := filepath.Join(negativeTestDir, dir, "Dockerfile")
    36  
    37  		df, err := os.Open(dockerfile)
    38  		if err != nil {
    39  			t.Fatalf("Dockerfile missing for %s: %v", dir, err)
    40  		}
    41  		defer df.Close()
    42  
    43  		d := Directive{LookingForDirectives: true}
    44  		SetEscapeToken(DefaultEscapeToken, &d)
    45  		_, err = Parse(df, &d)
    46  		if err == nil {
    47  			t.Fatalf("No error parsing broken dockerfile for %s", dir)
    48  		}
    49  	}
    50  }
    51  
    52  func TestTestData(t *testing.T) {
    53  	for _, dir := range getDirs(t, testDir) {
    54  		dockerfile := filepath.Join(testDir, dir, "Dockerfile")
    55  		resultfile := filepath.Join(testDir, dir, "result")
    56  
    57  		df, err := os.Open(dockerfile)
    58  		if err != nil {
    59  			t.Fatalf("Dockerfile missing for %s: %v", dir, err)
    60  		}
    61  		defer df.Close()
    62  
    63  		d := Directive{LookingForDirectives: true}
    64  		SetEscapeToken(DefaultEscapeToken, &d)
    65  		ast, err := Parse(df, &d)
    66  		if err != nil {
    67  			t.Fatalf("Error parsing %s's dockerfile: %v", dir, err)
    68  		}
    69  
    70  		content, err := ioutil.ReadFile(resultfile)
    71  		if err != nil {
    72  			t.Fatalf("Error reading %s's result file: %v", dir, err)
    73  		}
    74  
    75  		if runtime.GOOS == "windows" {
    76  			// CRLF --> CR to match Unix behavior
    77  			content = bytes.Replace(content, []byte{'\x0d', '\x0a'}, []byte{'\x0a'}, -1)
    78  		}
    79  
    80  		if ast.Dump()+"\n" != string(content) {
    81  			fmt.Fprintln(os.Stderr, "Result:\n"+ast.Dump())
    82  			fmt.Fprintln(os.Stderr, "Expected:\n"+string(content))
    83  			t.Fatalf("%s: AST dump of dockerfile does not match result", dir)
    84  		}
    85  	}
    86  }
    87  
    88  func TestParseWords(t *testing.T) {
    89  	tests := []map[string][]string{
    90  		{
    91  			"input":  {"foo"},
    92  			"expect": {"foo"},
    93  		},
    94  		{
    95  			"input":  {"foo bar"},
    96  			"expect": {"foo", "bar"},
    97  		},
    98  		{
    99  			"input":  {"foo\\ bar"},
   100  			"expect": {"foo\\ bar"},
   101  		},
   102  		{
   103  			"input":  {"foo=bar"},
   104  			"expect": {"foo=bar"},
   105  		},
   106  		{
   107  			"input":  {"foo bar 'abc xyz'"},
   108  			"expect": {"foo", "bar", "'abc xyz'"},
   109  		},
   110  		{
   111  			"input":  {`foo bar "abc xyz"`},
   112  			"expect": {"foo", "bar", `"abc xyz"`},
   113  		},
   114  		{
   115  			"input":  {"àöû"},
   116  			"expect": {"àöû"},
   117  		},
   118  		{
   119  			"input":  {`föo bàr "âbc xÿz"`},
   120  			"expect": {"föo", "bàr", `"âbc xÿz"`},
   121  		},
   122  	}
   123  
   124  	for _, test := range tests {
   125  		d := Directive{LookingForDirectives: true}
   126  		SetEscapeToken(DefaultEscapeToken, &d)
   127  		words := parseWords(test["input"][0], &d)
   128  		if len(words) != len(test["expect"]) {
   129  			t.Fatalf("length check failed. input: %v, expect: %q, output: %q", test["input"][0], test["expect"], words)
   130  		}
   131  		for i, word := range words {
   132  			if word != test["expect"][i] {
   133  				t.Fatalf("word check failed for word: %q. input: %q, expect: %q, output: %q", word, test["input"][0], test["expect"], words)
   134  			}
   135  		}
   136  	}
   137  }
   138  
   139  func TestLineInformation(t *testing.T) {
   140  	df, err := os.Open(testFileLineInfo)
   141  	if err != nil {
   142  		t.Fatalf("Dockerfile missing for %s: %v", testFileLineInfo, err)
   143  	}
   144  	defer df.Close()
   145  
   146  	d := Directive{LookingForDirectives: true}
   147  	SetEscapeToken(DefaultEscapeToken, &d)
   148  	ast, err := Parse(df, &d)
   149  	if err != nil {
   150  		t.Fatalf("Error parsing dockerfile %s: %v", testFileLineInfo, err)
   151  	}
   152  
   153  	if ast.StartLine != 5 || ast.EndLine != 31 {
   154  		fmt.Fprintf(os.Stderr, "Wrong root line information: expected(%d-%d), actual(%d-%d)\n", 5, 31, ast.StartLine, ast.EndLine)
   155  		t.Fatalf("Root line information doesn't match result.")
   156  	}
   157  	if len(ast.Children) != 3 {
   158  		fmt.Fprintf(os.Stderr, "Wrong number of child: expected(%d), actual(%d)\n", 3, len(ast.Children))
   159  		t.Fatalf("Root line information doesn't match result for %s", testFileLineInfo)
   160  	}
   161  	expected := [][]int{
   162  		{5, 5},
   163  		{11, 12},
   164  		{17, 31},
   165  	}
   166  	for i, child := range ast.Children {
   167  		if child.StartLine != expected[i][0] || child.EndLine != expected[i][1] {
   168  			t.Logf("Wrong line information for child %d: expected(%d-%d), actual(%d-%d)\n",
   169  				i, expected[i][0], expected[i][1], child.StartLine, child.EndLine)
   170  			t.Fatalf("Root line information doesn't match result.")
   171  		}
   172  	}
   173  }