func TestSelector_deep_nesting(t *testing.T) { ctx := NewContext() ctx.fset = token.NewFileSet() input := `a { c, d, e { f, g, h { m, n, o { color: blue; } } } }` out, err := ctx.runString("", input) if err != nil { t.Fatal(err) } e := `a c f m, a c f n, a c f o, a c g m, a c g n, a c g o, a c h m, a c h n, a c h o, a d f m, a d f n, a d f o, a d g m, a d g n, a d g o, a d h m, a d h n, a d h o, a e f m, a e f n, a e f o, a e g m, a e g n, a e g o, a e h m, a e h n, a e h o { color: blue; } ` if e != out { t.Fatalf("got:\n%s\nwanted:\n%s", out, e) } }
func TestDirective_each_paran(t *testing.T) { ctx := NewContext() ctx.fset = token.NewFileSet() input := `div { @each $i in (1 2 3 4 5) { i: $i; } } ` out, err := ctx.runString("", input) if err != nil { t.Fatal(err) } e := `div { i: 1; i: 2; i: 3; i: 4; i: 5; } ` if e != out { t.Fatalf("got:\n%s\nwanted:\n%s", out, e) } }
func TestDecl_if(t *testing.T) { ctx := NewContext() ctx.fset = token.NewFileSet() input := `$x: 1 2; @if type-of(nth($x, 2)) == number { div { background: gray; } } @else if type-of(nth($x, 2)) == string { div { background: blue; } } @else { div { background: green; } } ` ctx.SetMode(parser.Trace) out, err := ctx.runString("", input) if err != nil { t.Fatal(err) } e := `div { background: gray; } ` if e != out { t.Fatalf("got:\n%s\nwanted:\n%s", out, e) } }
func TestDecl_func_if(t *testing.T) { ctx := NewContext() ctx.fset = token.NewFileSet() input := `$x: true; @function foobar() { @if $x { $x: false !global; @return foo; } } div { content: foobar(); } ` ctx.SetMode(parser.Trace) out, err := ctx.runString("", input) if err != nil { t.Fatal(err) } e := `div { content: foo; } ` if e != out { t.Fatalf("got:\n%s\nwanted:\n%s", out, e) } }
func TestSelector_selector_interp(t *testing.T) { ctx := NewContext() ctx.fset = token.NewFileSet() input := `$x: oo, ba; $y: az, hu; f#{$x}r { p: 1; b#{$y}x { q: 2; mumble#{length($x) + length($y)} { r: 3; } } } ` out, err := ctx.runString("", input) if err != nil { t.Fatal(err) } e := `foo, bar { p: 1; } foo baz, foo hux, bar baz, bar hux { q: 2; } foo baz mumble4, foo hux mumble4, bar baz mumble4, bar hux mumble4 { r: 3; } ` if e != out { t.Fatalf("got:\n%s\nwanted:\n%s", out, e) } }
func testString(t *testing.T, in string, mode Mode) (*ast.File, *token.FileSet) { fset := token.NewFileSet() f, err := ParseFile(fset, "testfile", in, mode) if err != nil { t.Fatal(err) } return f, fset }
func TestUnitMath(t *testing.T) { const src = ` $a: 3px + 3px; div { width: $a; } ` f, err := ParseFile(token.NewFileSet(), "", src, 0) if err != nil { t.Fatal(err) } objects := map[string]ast.ObjKind{ "$color": ast.Var, "$list": ast.Var, } ast.Inspect(f, func(n ast.Node) bool { if spec, ok := n.(*ast.RuleSpec); ok { ast.Print(token.NewFileSet(), spec) } return true if ident, ok := n.(*ast.Ident); ok { return true obj := ident.Obj if obj == nil { if objects[ident.Name] != ast.Bad { t.Errorf("no object for %s", ident.Name) } return true } if obj.Name != ident.Name { t.Errorf("names don't match: obj.Name = %s, ident.Name = %s", obj.Name, ident.Name) } kind := objects[ident.Name] if obj.Kind != kind { t.Errorf("%s: obj.Kind = %s; want %s", ident.Name, obj.Kind, kind) } } return true }) }
func TestImports(t *testing.T) { for path, isValid := range imports { src := fmt.Sprintf("@import %s;", path) _, err := ParseFile(token.NewFileSet(), "", src, 0) // Trace switch { case err != nil && isValid: t.Errorf("ParseFile(%s): got %v; expected no error", src, err) case err == nil && !isValid: t.Errorf("ParseFile(%s): got no error; expected one", src) } } }
func runParse(t *testing.T, in string, e string) { ctx := NewContext() // ctx.SetMode(parser.Trace) ctx.fset = token.NewFileSet() bout, err := ctx.run("", in) if err != nil { t.Fatal(err) } out := string(bout) if e != out { t.Errorf("got:\n%q\nwanted:\n%q", out, e) } }
func (ctx *Context) run(path string, src interface{}) ([]byte, error) { ctx.fset = token.NewFileSet() // ctx.mode = parser.Trace pf, err := parser.ParseFile(ctx.fset, path, src, ctx.mode) if err != nil { return nil, err } ast.Walk(ctx, pf) lr, _ := utf8.DecodeLastRune(ctx.buf.Bytes()) _ = lr if ctx.buf.Len() > 0 && lr != '\n' { ctx.out("\n") } // ctx.printSels(pf.Decls) return ctx.buf.Bytes(), nil }
func TestSelector_combinators(t *testing.T) { ctx := NewContext() ctx.fset = token.NewFileSet() input := `a + b ~ c { color: red; } ` out, err := ctx.runString("", input) if err != nil { t.Fatal(err) } e := `a + b ~ c { color: red; } ` if e != out { t.Fatalf("got:\n%s\nwanted:\n%s", out, e) } }
func TestBinary_math(t *testing.T) { const src = ` $a: inspect(1 + 3); $b: inspect(3/1); $c: inspect(1/2 + 1/2); $d: inspect(2*2); $d: inspect(1*1/2); $e: inspect(1/2*1/2); $f: inspect(2*2/2*2); //$o: inspect(3px + 3px + 3px); ` f, err := ParseFile(token.NewFileSet(), "", src, 0|Trace) if err != nil { t.Fatal(err) } lits := []string{ "4", "3", "1", "4", "0.5", "0.25", "4", } var pos int ast.Inspect(f, func(n ast.Node) bool { if call, ok := n.(*ast.CallExpr); ok { // ident := call.Fun.(*ast.Ident) lit := call.Resolved.(*ast.BasicLit) val := lits[pos] pos++ if val != lit.Value { t.Errorf("useful ident here got: %s wanted %s", lit.Value, val) } } return true }) }
func TestSelector_many_nests(t *testing.T) { ctx := NewContext() ctx.fset = token.NewFileSet() input := `a, b { c, d { color: red; } } ` out, err := ctx.runString("", input) if err != nil { t.Fatal(err) } e := `a c, a d, b c, b d { color: red; } ` if e != out { t.Fatalf("got:\n%s\nwanted:\n%s", out, e) } }
func TestInterp(t *testing.T) { ctx := NewContext() ctx.fset = token.NewFileSet() input := `div { hello: #{123+321}; } ` out, err := ctx.runString("", input) if err != nil { t.Fatal(err) } e := `div { hello: 444; } ` if e != out { t.Fatalf("got:\n%s\nwanted:\n%s", out, e) } }
func register(s string, ch builtin.CallFunc, h builtin.CallHandle) { fset := token.NewFileSet() pf, err := ParseFile(fset, "", s, FuncOnly) if err != nil { if !strings.HasSuffix(err.Error(), "expected ';', found 'EOF'") { log.Fatal(err) } } d := &desc{c: call{ ch: ch, handle: h, }} ast.Walk(d, pf.Decls[0]) if d.err != nil { log.Fatal("failed to parse func description", d.err) } if _, ok := builtins[d.c.name]; ok { log.Println("already registered", d.c.name) } builtins[d.c.name] = d.c }
func TestSelector_comboampersand(t *testing.T) { ctx := NewContext() ctx.fset = token.NewFileSet() input := `div ~ b { & + & { color: red; } } ` out, err := ctx.runString("", input) if err != nil { t.Fatal("compilation fail", err) } e := `div ~ b + div ~ b { color: red; } ` if e != out { t.Fatalf("got:\n%s\nwanted:\n%s", out, e) } }
func TestSelector_singleampersand(t *testing.T) { ctx := NewContext() ctx.fset = token.NewFileSet() input := `div { & { color: red; } } ` out, err := ctx.runString("", input) if err != nil { t.Fatal(err) } e := `div { color: red; } ` if e != out { t.Fatalf("got:\n%s\nwanted:\n%s", out, e) } }
func TestSelector_nesting_child_group(t *testing.T) { ctx := NewContext() ctx.fset = token.NewFileSet() input := `a { b, c { color: red; } } ` out, err := ctx.runString("", input) if err != nil { t.Fatal(err) } e := `a b, a c { color: red; } ` if e != out { t.Fatalf("got:\n%s\nwanted:\n%s", out, e) } }
func TestSpec_files(t *testing.T) { inputs, err := filepath.Glob("../sass-spec/spec/basic/*/input.scss") if err != nil { t.Fatal(err) } mode := DeclarationErrors mode = Trace | ParseComments var name string for _, name = range inputs { if strings.Contains(name, "25_") && testing.Short() { // This is the last test we currently parse properly return } if !strings.Contains(name, "29_") { continue } if strings.Contains(name, "06_") { continue } if strings.Contains(name, "14_") { continue } // These are f****d things in Sass like lists if strings.Contains(name, "15_") { continue } // namespaces are wtf if strings.Contains(name, "24_") { continue } fmt.Println("Parsing", name) _, err := ParseFile(token.NewFileSet(), name, nil, mode) if err != nil { t.Fatalf("ParseFile(%s): %v", name, err) } fmt.Println("Parsed", name) } }
func TestSelector_inplace_nesting(t *testing.T) { ctx := NewContext() ctx.fset = token.NewFileSet() input := `hey, ho { foo &.goo { color: blue; } } ` out, err := ctx.runString("", input) if err != nil { t.Fatal(err) } e := `foo hey.goo, foo ho.goo { color: blue; } ` if e != out { t.Fatalf("got:\n%s\nwanted:\n%s", out, e) } }
func TestSelector_nesting_implicit_unary(t *testing.T) { ctx := NewContext() ctx.fset = token.NewFileSet() input := `a { > e { color: blue; } } ` out, err := ctx.runString("", input) if err != nil { t.Fatal(err) } e := `a > e { color: blue; } ` if e != out { t.Fatalf("got:\n%s\nwanted:\n%s", out, e) } }
func TestInterp_copy(t *testing.T) { ctx := NewContext() ctx.fset = token.NewFileSet() input := `div { @each $i in 1 2 { hello: text#{$i}; } } ` out, err := ctx.runString("", input) if err != nil { t.Fatal(err) } e := `div { hello: text1; hello: text2; } ` if e != out { t.Fatalf("got:\n%s\nwanted:\n%s", out, e) } }
func TestDirective_each(t *testing.T) { ctx := NewContext() ctx.fset = token.NewFileSet() input := `div { @each $i in a b c { i: $i; } } ` out, err := ctx.runString("", input) if err != nil { t.Fatal(err) } e := `div { i: a; i: b; i: c; } ` if e != out { t.Fatalf("got:\n%s\nwanted:\n%s", out, e) } }
func TestSelector_nesting_unary(t *testing.T) { // This is bizarre, may never support this odd syntax ctx := NewContext() ctx.fset = token.NewFileSet() input := `a { & > e { color: blue; } } ` out, err := ctx.runString("", input) if err != nil { t.Fatal(err) } e := `a > e { color: blue; } ` if e != out { t.Fatalf("got:\n%s\nwanted:\n%s", out, e) } }
func checkErrors(t *testing.T, filename string, input interface{}) { src, err := readSource(filename, input) if err != nil { t.Error(err) return } fset := token.NewFileSet() mode := DeclarationErrors | AllErrors _, err = ParseFile(fset, filename, src, mode) found, ok := err.(scanner.ErrorList) if err != nil && !ok { t.Error(err) return } found.RemoveMultiples() // we are expecting the following errors // (collect these after parsing a file so that it is found in the file set) expected := expectedErrors(t, fset, filename, src) // verify errors returned by the parser compareErrors(t, fset, expected, found) }
func TestObjects(t *testing.T) { const src = ` $color: red; $list: 1 2 $color; ` f, err := ParseFile(token.NewFileSet(), "", src, 0) if err != nil { t.Fatal(err) } objects := map[string]ast.ObjKind{ "$color": ast.Var, "$list": ast.Var, } ast.Inspect(f, func(n ast.Node) bool { if ident, ok := n.(*ast.Ident); ok { obj := ident.Obj if obj == nil { if objects[ident.Name] != ast.Bad { t.Errorf("no object for %s", ident.Name) } return true } if obj.Name != ident.Name { t.Errorf("names don't match: obj.Name = %s, ident.Name = %s", obj.Name, ident.Name) } kind := objects[ident.Name] if obj.Kind != kind { t.Errorf("%s: obj.Kind = %s; want %s", ident.Name, obj.Kind, kind) } } return true }) }
{token.MIXIN, "@mixin"},*/ // {token.SELECTOR, "foo($a,$b)"}, // {token.COLOR, "rgb(10,10,10)"}, } var source = func(tokens []elt) []byte { var src []byte for _, t := range tokens { src = append(src, t.lit...) src = append(src, whitespace...) } return src } var fset = token.NewFileSet() func newlineCount(s string) int { n := 0 for i := 0; i < len(s); i++ { if s[i] == '\n' { n++ } } return n } func checkPos(t *testing.T, lit string, p token.Pos, expected token.Position) { pos := fset.Position(p) if pos.Filename != expected.Filename { t.Errorf("bad filename for %q: got %s, expected %s", lit, pos.Filename, expected.Filename)
// ParseExpr is a convenience function for obtaining the AST of an expression x. // The position information recorded in the AST is undefined. The filename used // in error messages is the empty string. // func ParseExpr(x string) (ast.Expr, error) { return ParseExprFrom(token.NewFileSet(), "", []byte(x), 0) }
func printEach(ctx *Context, n ast.Node) { // surprise, not media but behavior is same! ctx.hiddenBlock = true fmt.Println("each...") ast.Print(token.NewFileSet(), n) }