package parser

import (
	"testing"

	"github.com/matryer/is"
)

type input struct {
	name   string
	markup string
	deps   []HeadBlockItem
}

func TestLexTextToken(t *testing.T) {
	tests := []struct {
		input
		output MarkupItem
	}{
		{
			input: input{
				name:   MarkupItemType[MUText],
				markup: "Hello",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUText],
				Data:        "Hello",
				Start:       0,
				End:         5,
				Line:        1,
				SelfClosing: true,
			},
		},
		{
			input: input{
				name:   MarkupItemType[MUText],
				markup: "Hello\n",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUText],
				Data:        "Hello\n",
				Start:       0,
				End:         6,
				Line:        1,
				SelfClosing: true,
			},
		},
	}

	is := is.New(t)

	for _, tt := range tests {
		lexer := LexMarkupBlock(tt.input.markup, tt.input.deps)

		item := <-lexer.items
		//fmt.Printf("\n\n\n\nOUT: %+v\n\nITM: %+v\n\n", tt.output, item)
		is.Equal(item, tt.output)
	}
}

func TestLexElementToken(t *testing.T) {
	tests := []struct {
		input
		output MarkupItem
	}{
		{
			input: input{
				name:   "Slot",
				markup: "<slot/>",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "slot",
				Start:       0,
				End:         7,
				Line:        1,
				SelfClosing: true,
			},
		},
		{
			input: input{
				name:   "Slot",
				markup: "<slot />",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "slot",
				Start:       0,
				End:         8,
				Line:        1,
				SelfClosing: true,
			},
		},
		{
			input: input{
				name:   "Slot",
				markup: "<slot type=\"static\"/>",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUSlot],
				Name:        "slot",
				Start:       0,
				End:         21,
				Line:        1,
				SelfClosing: true,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "type",
						Start: 6,
						End:   19,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Data:  "static",
								Start: 12,
								End:   18,
								Line:  1,
							},
						},
					},
				},
			},
		},
		{
			input: input{
				name:   "Slot",
				markup: "<slot type=\"static\" />",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUSlot],
				Name:        "slot",
				Start:       0,
				End:         22,
				Line:        1,
				SelfClosing: true,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "type",
						Start: 6,
						End:   19,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Data:  "static",
								Start: 12,
								End:   18,
								Line:  1,
							},
						},
					},
				},
			},
		},
		{
			input: input{
				name:   "Slot",
				markup: "<slot type=static/>",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUSlot],
				Name:        "slot",
				Start:       0,
				End:         19,
				Line:        1,
				SelfClosing: true,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "type",
						Start: 6,
						End:   17,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Data:  "static",
								Start: 11,
								End:   17,
								Line:  1,
							},
						},
					},
				},
			},
		},
		{
			input: input{
				name:   "Slot",
				markup: "<slot type=static />",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUSlot],
				Name:        "slot",
				Start:       0,
				End:         20,
				Line:        1,
				SelfClosing: true,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "type",
						Start: 6,
						End:   17,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Data:  "static",
								Start: 11,
								End:   17,
								Line:  1,
							},
						},
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<h1>",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "h1",
				Start:       0,
				End:         4,
				Line:        1,
				SelfClosing: false,
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<h1 >",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "h1",
				Start:       0,
				End:         5,
				Line:        1,
				SelfClosing: false,
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<h1/>",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "h1",
				Start:       0,
				End:         5,
				Line:        1,
				SelfClosing: true,
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<h1 />",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "h1",
				Start:       0,
				End:         6,
				Line:        1,
				SelfClosing: true,
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<h1 bool>",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "h1",
				Start:       0,
				End:         9,
				Line:        1,
				SelfClosing: false,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "bool",
						Start: 4,
						End:   8,
						Line:  1,
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<h1 bool two>",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "h1",
				Start:       0,
				End:         13,
				Line:        1,
				SelfClosing: false,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "bool",
						Start: 4,
						End:   8,
						Line:  1,
					},
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "two",
						Start: 9,
						End:   12,
						Line:  1,
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<img bool >",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "img",
				Start:       0,
				End:         11,
				Line:        1,
				SelfClosing: false,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "bool",
						Start: 5,
						End:   9,
						Line:  1,
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<h1 bool two >",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "h1",
				Start:       0,
				End:         14,
				Line:        1,
				SelfClosing: false,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "bool",
						Start: 4,
						End:   8,
						Line:  1,
					},
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "two",
						Start: 9,
						End:   12,
						Line:  1,
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<h1 bool/>",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "h1",
				Start:       0,
				End:         10,
				Line:        1,
				SelfClosing: true,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "bool",
						Start: 4,
						End:   8,
						Line:  1,
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<h1 bool two/>",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "h1",
				Start:       0,
				End:         14,
				Line:        1,
				SelfClosing: true,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "bool",
						Start: 4,
						End:   8,
						Line:  1,
					},
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "two",
						Start: 9,
						End:   12,
						Line:  1,
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<h1 bool />",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "h1",
				Start:       0,
				End:         11,
				Line:        1,
				SelfClosing: true,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "bool",
						Start: 4,
						End:   8,
						Line:  1,
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<h1 bool two />",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "h1",
				Start:       0,
				End:         15,
				Line:        1,
				SelfClosing: true,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "bool",
						Start: 4,
						End:   8,
						Line:  1,
					},
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "two",
						Start: 9,
						End:   12,
						Line:  1,
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<img id=\"unique\">",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "img",
				Start:       0,
				End:         17,
				Line:        1,
				SelfClosing: false,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "id",
						Start: 5,
						End:   16,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Start: 9,
								End:   15,
								Line:  1,
								Data:  "unique",
							},
						},
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<img id=\"unique\" class=\"sel\">",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "img",
				Start:       0,
				End:         29,
				Line:        1,
				SelfClosing: false,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "id",
						Start: 5,
						End:   16,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Start: 9,
								End:   15,
								Line:  1,
								Data:  "unique",
							},
						},
					},
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "class",
						Start: 17,
						End:   28,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Start: 24,
								End:   27,
								Line:  1,
								Data:  "sel",
							},
						},
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<img id=\"unique\" >",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "img",
				Start:       0,
				End:         18,
				Line:        1,
				SelfClosing: false,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "id",
						Start: 5,
						End:   16,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Start: 9,
								End:   15,
								Line:  1,
								Data:  "unique",
							},
						},
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<img id=\"unique\" class=\"sel\" >",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "img",
				Start:       0,
				End:         30,
				Line:        1,
				SelfClosing: false,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "id",
						Start: 5,
						End:   16,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Start: 9,
								End:   15,
								Line:  1,
								Data:  "unique",
							},
						},
					},
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "class",
						Start: 17,
						End:   28,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Start: 24,
								End:   27,
								Line:  1,
								Data:  "sel",
							},
						},
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<img id=\"unique\" />",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "img",
				Start:       0,
				End:         19,
				Line:        1,
				SelfClosing: true,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "id",
						Start: 5,
						End:   16,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Start: 9,
								End:   15,
								Line:  1,
								Data:  "unique",
							},
						},
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<img id=\"unique\" class=\"sel\" />",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "img",
				Start:       0,
				End:         31,
				Line:        1,
				SelfClosing: true,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "id",
						Start: 5,
						End:   16,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Start: 9,
								End:   15,
								Line:  1,
								Data:  "unique",
							},
						},
					},
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "class",
						Start: 17,
						End:   28,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Start: 24,
								End:   27,
								Line:  1,
								Data:  "sel",
							},
						},
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<img id=unique/>",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "img",
				Start:       0,
				End:         16,
				Line:        1,
				SelfClosing: true,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "id",
						Start: 5,
						End:   14,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Start: 8,
								End:   14,
								Line:  1,
								Data:  "unique",
							},
						},
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<img id=unique class=sel/>",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "img",
				Start:       0,
				End:         26,
				Line:        1,
				SelfClosing: true,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "id",
						Start: 5,
						End:   14,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Start: 8,
								End:   14,
								Line:  1,
								Data:  "unique",
							},
						},
					},
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "class",
						Start: 15,
						End:   24,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Start: 21,
								End:   24,
								Line:  1,
								Data:  "sel",
							},
						},
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<img id=unique >",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "img",
				Start:       0,
				End:         16,
				Line:        1,
				SelfClosing: false,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "id",
						Start: 5,
						End:   14,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Start: 8,
								End:   14,
								Line:  1,
								Data:  "unique",
							},
						},
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<img id=unique class=sel >",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "img",
				Start:       0,
				End:         26,
				Line:        1,
				SelfClosing: false,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "id",
						Start: 5,
						End:   14,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Start: 8,
								End:   14,
								Line:  1,
								Data:  "unique",
							},
						},
					},
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "class",
						Start: 15,
						End:   24,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Start: 21,
								End:   24,
								Line:  1,
								Data:  "sel",
							},
						},
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<img id=unique />",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "img",
				Start:       0,
				End:         17,
				Line:        1,
				SelfClosing: true,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "id",
						Start: 5,
						End:   14,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Start: 8,
								End:   14,
								Line:  1,
								Data:  "unique",
							},
						},
					},
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<img id=unique class=sel />",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "img",
				Start:       0,
				End:         27,
				Line:        1,
				SelfClosing: true,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "id",
						Start: 5,
						End:   14,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Start: 8,
								End:   14,
								Line:  1,
								Data:  "unique",
							},
						},
					},
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "class",
						Start: 15,
						End:   24,
						Line:  1,
						Value: []MarkupItem{
							{
								Typ:   "Text",
								Start: 21,
								End:   24,
								Line:  1,
								Data:  "sel",
							},
						},
					},
				},
			},
		},
	}

	is := is.New(t)

	for _, tt := range tests {
		lexer := LexMarkupBlock(tt.input.markup, tt.input.deps)

		for item := range lexer.items {
			if item.Typ == MarkupItemType[MarkupEOF] {
				break
			}

			// fmt.Printf("\n\nOUT: %+v\n\nITM: %+v\n\n\n\n", tt.output, item)
			is.Equal(tt.output, item)
		}
	}
}

func TestLexInlineComponentToken(t *testing.T) {
	tests := []struct {
		input
		output MarkupItem
	}{
		{
			input: input{
				name:   "Greet",
				markup: "<Greet>",
				deps: []HeadBlockItem{
					{
						Kind: Kind{
							Name:    "link",
							RelType: "rel",
							Value:   "import",
						},
						Attrs: map[string]string{
							"name": "Greet",
						},
						Path: Path{
							PathType: "href",
							RelPath:  "./greet.html",
						},
					},
				},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUInlineComponent],
				Name:        "Greet",
				Start:       0,
				End:         7,
				Line:        1,
				SelfClosing: false,
			},
		},
		{
			input: input{
				name:   "Greet",
				markup: "<Greet >",
				deps: []HeadBlockItem{
					{
						Kind: Kind{
							Name:    "link",
							RelType: "rel",
							Value:   "import",
						},
						Attrs: map[string]string{
							"name": "Greet",
						},
						Path: Path{
							PathType: "href",
							RelPath:  "./greet.html",
						},
					},
				},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUInlineComponent],
				Name:        "Greet",
				Start:       0,
				End:         8,
				Line:        1,
				SelfClosing: false,
			},
		},
		{
			input: input{
				name:   "Greet",
				markup: "<Greet/>",
				deps: []HeadBlockItem{
					{
						Kind: Kind{
							Name:    "link",
							RelType: "rel",
							Value:   "import",
						},
						Attrs: map[string]string{
							"name": "Greet",
						},
						Path: Path{
							PathType: "href",
							RelPath:  "./greet.html",
						},
					},
				},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUInlineComponent],
				Name:        "Greet",
				Start:       0,
				End:         8,
				Line:        1,
				SelfClosing: true,
			},
		},
		{
			input: input{
				name:   "Greet",
				markup: "<Greet />",
				deps: []HeadBlockItem{
					{
						Kind: Kind{
							Name:    "link",
							RelType: "rel",
							Value:   "import",
						},
						Attrs: map[string]string{
							"name": "Greet",
						},
						Path: Path{
							PathType: "href",
							RelPath:  "./greet.html",
						},
					},
				},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUInlineComponent],
				Name:        "Greet",
				Start:       0,
				End:         9,
				Line:        1,
				SelfClosing: true,
			},
		},
		{
			input: input{
				name:   "Greet",
				markup: "<Greet bool>",
				deps: []HeadBlockItem{
					{
						Kind: Kind{
							Name:    "link",
							RelType: "rel",
							Value:   "import",
						},
						Attrs: map[string]string{
							"name": "Greet",
						},
						Path: Path{
							PathType: "href",
							RelPath:  "./greet.html",
						},
					},
				},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUInlineComponent],
				Name:        "Greet",
				Start:       0,
				End:         12,
				Line:        1,
				SelfClosing: false,
				Attributes: []MarkupItem{
					{
						Typ:   MarkupItemType[MUAttribute],
						Name:  "bool",
						Start: 7,
						End:   11,
						Line:  1,
					},
				},
			},
		},
		{
			input: input{
				name:   "SlotComponent",
				markup: "<SlotComponent>",
				deps: []HeadBlockItem{
					{
						Kind: Kind{
							Name:    "link",
							RelType: "rel",
							Value:   "import",
						},
						Attrs: map[string]string{
							"name": "SlotComponent",
						},
						Path: Path{
							PathType: "href",
							RelPath:  "./slot-component.html",
						},
					},
				},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUInlineComponent],
				Name:        "SlotComponent",
				Start:       0,
				End:         15,
				Line:        1,
				SelfClosing: false,
			},
		},
		{
			input: input{
				name:   "Links",
				markup: "<Links></Links>",
				deps: []HeadBlockItem{
					{
						Kind: Kind{
							Name:    "link",
							RelType: "rel",
							Value:   "import",
						},
						Attrs: map[string]string{
							"name": "Links",
						},
						Path: Path{
							PathType: "href",
							RelPath:  "./links.html",
						},
					},
				},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUInlineComponent],
				Name:        "Links",
				Start:       0,
				End:         15,
				Line:        1,
				SelfClosing: true,
			},
		},
		{
			input: input{
				name:   "Links",
				markup: "<Links></Links>",
				deps: []HeadBlockItem{
					{
						Kind: Kind{
							Name:    "meta",
							RelType: "",
							Value:   "",
						},
						Attrs: map[string]string{
							"content": "John Doe",
							"name":    "author",
						},
						Path: Path{
							PathType: "",
							RelPath:  "",
						},
					},
					{
						Kind: Kind{
							Name:    "link",
							RelType: "rel",
							Value:   "import",
						},
						Attrs: map[string]string{
							"name": "Links",
						},
						Path: Path{
							PathType: "href",
							RelPath:  "./links.html",
						},
					},
				},
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUInlineComponent],
				Name:        "Links",
				Start:       0,
				End:         15,
				Line:        1,
				SelfClosing: true,
			},
		},
		{
			input: input{
				name:   "Div",
				markup: "<div></div>",
			},
			output: MarkupItem{
				Typ:         MarkupItemType[MUElement],
				Name:        "div",
				Start:       0,
				End:         11,
				Line:        1,
				SelfClosing: true,
			},
		},
	}

	is := is.New(t)

	for _, tt := range tests {
		lexer := LexMarkupBlock(tt.input.markup, tt.input.deps)

		item := <-lexer.items

		// fmt.Printf("\n\n\n\nEXP: %+v\n\nRES: %+v\n\n", tt.output, item)
		is.Equal(item, tt.output)
	}
}

func TestLexClosingTagToken(t *testing.T) {
	tests := []struct {
		input
		output MarkupItem
	}{
		{
			input: input{
				name:   "Element",
				markup: "</h1>",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:   "ClosingTag",
				Name:  "h1",
				Start: 0,
				End:   5,
				Line:  1,
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "</h1 >",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:   "ClosingTag",
				Name:  "h1",
				Start: 0,
				End:   6,
				Line:  1,
			},
		},
	}

	is := is.New(t)

	for _, tt := range tests {
		lexer := LexMarkupBlock(tt.input.markup, tt.input.deps)

		item := <-lexer.items

		// fmt.Printf("\n\n\n\nOUT: %+v\n\nITM: %+v\n\n", tt.output, item)
		is.Equal(item, tt.output)
	}
}

func TestLexMarkupComment(t *testing.T) {
	tests := []struct {
		input
		output MarkupItem
	}{
		{
			input: input{
				name:   "Comment",
				markup: "<!-- in comment -->",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         "Comment",
				Data:        "in comment",
				Start:       0,
				End:         19,
				Line:        1,
				SelfClosing: true,
			},
		},
		{
			input: input{
				name:   "Comment",
				markup: "<!--\n\tmulti\n\tline\n\tcomment\n-->",
				deps:   []HeadBlockItem{},
			},
			output: MarkupItem{
				Typ:         "Comment",
				Data:        "multi\n\tline\n\tcomment",
				Start:       0,
				End:         30,
				Line:        1,
				SelfClosing: true,
			},
		},
	}

	is := is.New(t)

	for _, tt := range tests {
		lexer := LexMarkupBlock(tt.input.markup, tt.input.deps)
		item := <-lexer.items

		// fmt.Printf("\n\n\n\nOUT: %+v\n\nITM: %+v\n\n", tt.output, item)
		is.Equal(item, tt.output)
	}
}

func TestMarkupLexer(t *testing.T) {
	tests := []struct {
		input
		output []MarkupItem
	}{
		{
			input: input{
				name:   "Element",
				markup: "Hello",
				deps:   []HeadBlockItem{},
			},
			output: []MarkupItem{
				{
					Typ:         MarkupItemType[MUText],
					Data:        "Hello",
					Start:       0,
					End:         5,
					Line:        1,
					SelfClosing: true,
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<h1>Hello</h1>",
				deps:   []HeadBlockItem{},
			},
			output: []MarkupItem{
				{
					Typ:         MarkupItemType[MUElement],
					Name:        "h1",
					Start:       0,
					End:         4,
					Line:        1,
					SelfClosing: false,
				},
				{
					Typ:         MarkupItemType[MUText],
					Data:        "Hello",
					Start:       4,
					End:         9,
					Line:        1,
					SelfClosing: true,
				},
				{
					Typ:         MarkupItemType[MUClosingTag],
					Name:        "h1",
					Start:       9,
					End:         14,
					Line:        1,
					SelfClosing: false,
				},
			},
		},
		{
			input: input{
				name:   "Element",
				markup: "<h1>Hello</h1><p>lorem</p>",
				deps:   []HeadBlockItem{},
			},
			output: []MarkupItem{
				{
					Typ:         MarkupItemType[MUElement],
					Name:        "h1",
					Start:       0,
					End:         4,
					Line:        1,
					SelfClosing: false,
				},
				{
					Typ:         MarkupItemType[MUText],
					Data:        "Hello",
					Start:       4,
					End:         9,
					Line:        1,
					SelfClosing: true,
				},
				{
					Typ:         MarkupItemType[MUClosingTag],
					Name:        "h1",
					Start:       9,
					End:         14,
					Line:        1,
					SelfClosing: false,
				},
				{
					Typ:         MarkupItemType[MUElement],
					Name:        "p",
					Start:       14,
					End:         17,
					Line:        1,
					SelfClosing: false,
				},
				{
					Typ:         MarkupItemType[MUText],
					Data:        "lorem",
					Start:       17,
					End:         22,
					Line:        1,
					SelfClosing: true,
				},
				{
					Typ:         MarkupItemType[MUClosingTag],
					Name:        "p",
					Start:       22,
					End:         26,
					Line:        1,
					SelfClosing: false,
				},
			},
		},
	}

	is := is.New(t)

	for _, tt := range tests {
		lexer := LexMarkupBlock(tt.input.markup, tt.input.deps)

		i := 0
		for item := range lexer.items {
			if item.Typ == MarkupItemType[MarkupEOF] {
				break
			}

			// fmt.Printf("\n\n\n\nOUT: %+v\n\nITM: %+v\n\n", tt.output[i], item)
			is.Equal(item, tt.output[i])
			i++
		}
	}
}
