Example #1
0
func Test_FileNode_Signature(t *testing.T) {
	cleanup := testutils.Chtemp()
	defer cleanup()

	testutils.Mkdirs("d1", "d2")
	testutils.Mkfile("d1", "empty", "")
	testutils.Mkfile("d2", "stuff", "foo\n")

	node1 := NewFileNode("d1/empty")
	node2 := NewFileNode("d2/stuff")
	node3 := NewFileNode("nonexistent")

	expect := []byte{}
	hash := fnv.New64a()
	assert.Equal(t, 8, hash.Size())
	expect = hash.Sum(expect)

	sig, err := node1.Signature()
	assert.Nil(t, err)
	assert.Equal(t, expect, sig)

	hash.Write([]byte{'f', 'o', 'o', '\n'})
	expect = expect[:0]
	expect = hash.Sum(expect)
	sig, err = node2.Signature()
	assert.Nil(t, err)
	assert.Equal(t, expect, sig)

	// make sure it's cached, i.e. changes to the file are not seen by
	// the same FileNode object in the same process
	testutils.Mkfile("d2", "stuff", "fooo\n")
	sig, err = node2.Signature()
	assert.Nil(t, err)
	assert.Equal(t, expect, sig)

	// in fact, even if the file disappears, we still have its signature
	err = os.Remove("d2/stuff")
	if err != nil {
		panic(err)
	}
	sig, err = node2.Signature()
	assert.Nil(t, err)
	assert.Equal(t, expect, sig)

	sig, err = node3.Signature()
	assert.NotNil(t, err)
	assert.Equal(t, "open nonexistent: no such file or directory", err.Error())
}
Example #2
0
func TestParse_internal_newlines(t *testing.T) {
	// newlines in a function call are invisible to the parser
	tmpdir, cleanup := testutils.Mktemp()
	defer cleanup()

	script := `
main {
  x(
a.b
    )
}
`
	fn := testutils.Mkfile(tmpdir, "newlines.fubsy", script)
	ast, err := Parse(fn)
	assert.Equal(t, 0, len(err))

	expect := &ASTRoot{
		children: []ASTNode{
			&ASTPhase{
				name: "main",
				children: []ASTNode{
					&ASTFunctionCall{
						function: &ASTName{name: "x"},
						args: []ASTExpression{
							&ASTSelection{
								container: &ASTName{name: "a"},
								member:    "b",
							}}}},
			}}}
	assertASTEqual(t, expect, ast)
}
Example #3
0
func TestParse_valid_sequence(t *testing.T) {
	tmpdir, cleanup := testutils.Mktemp()
	defer cleanup()

	// sequence of top-level children
	script := `
main {
"boo"
}
plugin foo {{{
o'malley & friends
}}}
blob {
 "meep"
 }`
	fn := testutils.Mkfile(tmpdir, "valid_2.fubsy", script)
	ast, errs := Parse(fn)
	testutils.NoErrors(t, errs)

	expect := &ASTRoot{children: []ASTNode{
		&ASTPhase{
			name:     "main",
			children: []ASTNode{&ASTString{value: "boo"}}},
		&ASTInline{
			lang: "foo", content: "o'malley & friends"},
		&ASTPhase{
			name:     "blob",
			children: []ASTNode{&ASTString{value: "meep"}}},
	}}
	assertASTEqual(t, expect, ast)
}
Example #4
0
// this one tries to exercise many token types and grammar rules
func TestParse_omnibus_1(t *testing.T) {
	tmpdir, cleanup := testutils.Mktemp()
	defer cleanup()

	script := `
# start with a comment
import foo
import foo.bar.baz

     
# blank lines are OK!
plugin funky {{{
any ol' crap! "bring it on, 
dude" ...
}}}
main {
  a   =("foo") + b
  c=(d.e)  ()
x.y.z
  <
    lib1/*.c
    lib2/**/*.c
  >
}
`
	fn := testutils.Mkfile(tmpdir, "omnibus_1.fubsy", script)
	ast, err := Parse(fn)
	assert.Equal(t, 0, len(err))

	expect :=
		`ASTRoot {
  ASTImport[foo]
  ASTImport[foo.bar.baz]
  ASTInline[funky] {{{
    any ol' crap! "bring it on, 
    dude" ...
  }}}
  ASTPhase[main] {
    ASTAssignment[a]
      ASTAdd
      op1:
        ASTString[foo]
      op2:
        ASTName[b]
    ASTAssignment[c]
      ASTFunctionCall[d.e] (0 args)
    ASTSelection[x.y: z]
    ASTFileFinder[lib1/*.c lib2/**/*.c]
  }
}
`
	var actual_ bytes.Buffer
	ast.Dump(&actual_, "")
	actual := actual_.String()
	if expect != actual {
		t.Errorf("expected AST:\n%s\nbut got:\n%s", expect, actual)
	}
}
Example #5
0
func TestParse_omnibus_2(t *testing.T) {
	tmpdir, cleanup := testutils.Mktemp()
	defer cleanup()

	script := `
main {
  headers = <*.h>

  a + b : <*.c> + headers {
    x = a
    "cc $x"
    f(a, b)
  }
}
`
	fn := testutils.Mkfile(tmpdir, "omnibus_2.fubsy", script)
	ast, err := Parse(fn)
	assert.Equal(t, 0, len(err))

	expect :=
		`ASTRoot {
  ASTPhase[main] {
    ASTAssignment[headers]
      ASTFileFinder[*.h]
    ASTBuildRule {
    targets:
      ASTAdd
      op1:
        ASTName[a]
      op2:
        ASTName[b]
    sources:
      ASTAdd
      op1:
        ASTFileFinder[*.c]
      op2:
        ASTName[headers]
    actions:
      ASTAssignment[x]
        ASTName[a]
      ASTString[cc $x]
      ASTFunctionCall[f] (2 args)
        ASTName[a]
        ASTName[b]
    }
  }
}
`
	var actual_ bytes.Buffer
	ast.Dump(&actual_, "")
	actual := actual_.String()
	if expect != actual {
		t.Errorf("expected AST:\n%s\nbut got:\n%s", expect, actual)
	}
}
Example #6
0
func TestParse_invalid_1(t *testing.T) {
	tmpdir, cleanup := testutils.Mktemp()
	defer cleanup()

	// invalid: no closing rbracket
	script := `
main{
"borf"
`
	fn := testutils.Mkfile(tmpdir, "invalid_1.fubsy", script)
	_, err := Parse(fn)
	expect := fn + ":4: syntax error (near EOF)"
	assertOneError(t, expect, err)
}
Example #7
0
func Test_FileNode_Changed(t *testing.T) {
	// this is really a test of Signature() + Changed() together, because
	// Changed() itself is so trivial that testing it is no challenge
	cleanup := testutils.Chtemp()
	defer cleanup()

	testutils.Mkfile(".", "stuff.txt", "blah blah blah\n")
	node := NewFileNode("stuff.txt")
	osig, err := node.Signature()
	assert.Nil(t, err)

	// construct a new FileNode so the cache is lost
	node = NewFileNode("stuff.txt")
	nsig, err := node.Signature()
	assert.Nil(t, err)
	assert.False(t, node.Changed(osig, nsig))

	// modify the file and repeat
	testutils.Mkfile(".", "stuff.txt", "blah blah blah\nblah")
	node = NewFileNode("stuff.txt")
	nsig, err = node.Signature()
	assert.Nil(t, err)
	assert.True(t, node.Changed(osig, nsig))
}
Example #8
0
func TestParse_invalid_2(t *testing.T) {
	tmpdir, cleanup := testutils.Mktemp()
	defer cleanup()

	// invalid: bad token
	script := `
main{
 *&! "whizz"
}`
	fn := testutils.Mkfile(tmpdir, "invalid_2.fubsy", script)
	_, err := Parse(fn)
	expect := fn + ":3: syntax error (near *&!)"
	assertOneError(t, expect, err)
	reset()
}
Example #9
0
func TestParse_valid_1(t *testing.T) {
	tmpdir, cleanup := testutils.Mktemp()
	defer cleanup()

	// dead simple: a single top-level element
	script := `
main {
<meep>

}
`
	fn := testutils.Mkfile(tmpdir, "valid_1.fubsy", script)
	expect := &ASTRoot{children: []ASTNode{
		&ASTPhase{name: "main", children: []ASTNode{
			&ASTFileFinder{patterns: []string{"meep"}}}}}}
	ast, err := Parse(fn)
	assert.Equal(t, 0, len(err))
	assertASTEqual(t, expect, ast)
	eofloc := ast.EOF().Location()
	assert.True(t, strings.HasSuffix(eofloc.ErrorPrefix(), "valid_1.fubsy:6: "))
}