<commit_before>package template

import (
	"bytes"
	"fmt"
	goparser "go/parser"
	"go/token"
	"io/ioutil"
	"testing"

	"github.com/vetcher/godecl"
	"github.com/vetcher/godecl/types"
)

func findInterface(file *types.File, ifaceName string) *types.Interface {
	for i := range file.Interfaces {
		if file.Interfaces[i].Name == ifaceName {
			return &file.Interfaces[i]
		}
	}
	return nil
}

func loadInterface(sourceFile, ifaceName string) (*types.Interface, error) {
	src, err := ioutil.ReadFile(sourceFile)
	if err != nil {
		return nil, fmt.Errorf("read source file error: %v", err)
	}
	tree, err := goparser.ParseFile(token.NewFileSet(), "", src, 0)
	if err != nil {
		return nil, fmt.Errorf("unable to parse file: %v", err)
	}
	// TODO(nicolai): Figure out if packagePath needs to be anything
	packagePath := ""
	info, err := godecl.ParseAstFile(tree, packagePath)
	if err != nil {
		fmt.Printf("error when parsing info from file: %v\n", err)
	}
	i := findInterface(info, ifaceName)
	if i == nil {
		return nil, fmt.Errorf("could not find %s interface", ifaceName)
	}
	return i, nil
}

func TestTemplates(t *testing.T) {
	fs, err := loadInterface("service.go.txt", "StringService")
	if err != nil {
		t.Fatal(err)
	}
	allTemplateTests := []struct {
		TestName    string
		Template    Template
		OutFilePath string
	}{
		{
			TestName: "Endpoints",
			Template: &endpointsTemplate{
				Info: &GenerationInfo{
					ServiceImportPackageName: "stringsvc",
				}},
			OutFilePath: "endpoints.go.txt",
		},
		{
			TestName: "Exchange",
			Template: &exchangeTemplate{
				Info: &GenerationInfo{
					ServiceImportPackageName: "stringsvc",
				}},
			OutFilePath: "exchange.go.txt",
		},
		{
			TestName: "Middleware",
			Template: &middlewareTemplate{
				Info: &GenerationInfo{
					ServiceImportPath: "github.com/devimteam/microgen/example/svc",
				}},
			OutFilePath: "middleware.go.txt",
		},
		{
			TestName: "Logging",
			Template: &loggingTemplate{
				Info: &GenerationInfo{
					ServiceImportPath: "github.com/devimteam/microgen/example/svc",
				}},
			OutFilePath: "logging.go.txt",
		},
		{
			TestName: "GRPC Server",
			Template: &gRPCServerTemplate{
				Info: &GenerationInfo{
					ServiceImportPackageName: "stringsvc",
				}},
			OutFilePath: "grpc_server.go.txt",
		},
		{
			TestName: "GRPC Client",
			Template: &gRPCClientTemplate{
				Info: &GenerationInfo{
					ServiceImportPath: "github.com/devimteam/microgen/example/svc",
				}},
			OutFilePath: "grpc_client.go.txt",
		},
		{
			TestName: "GRPC Converter",
			Template: &gRPCEndpointConverterTemplate{
				Info: &GenerationInfo{
					ServiceImportPath:        "github.com/devimteam/microgen/example/svc",
					ServiceImportPackageName: "stringsvc",
				}},
			OutFilePath: "grpc_converters.go.txt",
		},
		{
			TestName: "GRPC Type Converter",
			Template: &stubGRPCTypeConverterTemplate{
				Info: &GenerationInfo{
					ServiceImportPath: "github.com/devimteam/microgen/example/svc",
				}},
			OutFilePath: "grpc_type.go.txt",
		},
	}
	for _, test := range allTemplateTests {
		t.Run(test.TestName, func(t *testing.T) {
			out, err := ioutil.ReadFile(test.OutFilePath)
			if err != nil {
				t.Fatalf("read out file error: %v", err)
			}

			buf := bytes.NewBuffer([]byte{})
			gen := NewGenerator([]Template{test.Template}, fs, WriterStrategy(buf))
			err = gen.Generate()
			if err != nil {
				t.Fatalf("unable to generate: %v", err)
			}
			if buf.String() != string(out[:]) {
				t.Errorf("Got:\n/////////\n%s\n/////////\nExpected:\n/////////\n%s\n/////////", buf.String(), string(out[:]))
				t.Errorf("1: Got(bytes), 2: Expected(bytes):\n/////////\n1: %v\n2: %v\n/////////", buf.Bytes(), out[:])
				x, y, z, line := findDifference(buf.String(), string(out[:]))
				t.Errorf("line:pos:raw %d:%d:%d %d!=%d %v\n`%s`", x+1, y+1, z, buf.Bytes()[z], out[z], len(buf.String()) == len(string(out[:])), line)
			}
		})
	}
}

func findDifference(first, second string) (line int, pos int, raw int, strLine string) {
	for i, sym := range first {
		if first[i] != second[i] {
			return
		}
		if sym == '\n' {<commit_msg>WIP: Use new function NewGenUnit<commit_after>package template

import (
	"bytes"
	"fmt"
	goparser "go/parser"
	"go/token"
	"io/ioutil"
	"testing"

	"github.com/devimteam/microgen/generator"
	"github.com/vetcher/godecl"
	"github.com/vetcher/godecl/types"
)

func findInterface(file *types.File, ifaceName string) *types.Interface {
	for i := range file.Interfaces {
		if file.Interfaces[i].Name == ifaceName {
			return &file.Interfaces[i]
		}
	}
	return nil
}

func loadInterface(sourceFile, ifaceName string) (*types.Interface, error) {
	src, err := ioutil.ReadFile(sourceFile)
	if err != nil {
		return nil, fmt.Errorf("read source file error: %v", err)
	}
	tree, err := goparser.ParseFile(token.NewFileSet(), "", src, 0)
	if err != nil {
		return nil, fmt.Errorf("unable to parse file: %v", err)
	}
	// TODO(nicolai): Figure out if packagePath needs to be anything
	packagePath := ""
	info, err := godecl.ParseAstFile(tree, packagePath)
	if err != nil {
		fmt.Printf("error when parsing info from file: %v\n", err)
	}
	i := findInterface(info, ifaceName)
	if i == nil {
		return nil, fmt.Errorf("could not find %s interface", ifaceName)
	}
	return i, nil
}

func TestTemplates(t *testing.T) {
	fs, err := loadInterface("service.go.txt", "StringService")
	if err != nil {
		t.Fatal(err)
	}
	allTemplateTests := []struct {
		TestName    string
		Template    Template
		OutFilePath string
	}{
		{
			TestName: "Endpoints",
			Template: &endpointsTemplate{
				Info: &GenerationInfo{
					ServiceImportPackageName: "stringsvc",
				}},
			OutFilePath: "endpoints.go.txt",
		},
		{
			TestName: "Exchange",
			Template: &exchangeTemplate{
				Info: &GenerationInfo{
					ServiceImportPackageName: "stringsvc",
				}},
			OutFilePath: "exchange.go.txt",
		},
		{
			TestName: "Middleware",
			Template: &middlewareTemplate{
				Info: &GenerationInfo{
					ServiceImportPath: "github.com/devimteam/microgen/example/svc",
				}},
			OutFilePath: "middleware.go.txt",
		},
		{
			TestName: "Logging",
			Template: &loggingTemplate{
				Info: &GenerationInfo{
					ServiceImportPath: "github.com/devimteam/microgen/example/svc",
				}},
			OutFilePath: "logging.go.txt",
		},
		{
			TestName: "GRPC Server",
			Template: &gRPCServerTemplate{
				Info: &GenerationInfo{
					ServiceImportPackageName: "stringsvc",
				}},
			OutFilePath: "grpc_server.go.txt",
		},
		{
			TestName: "GRPC Client",
			Template: &gRPCClientTemplate{
				Info: &GenerationInfo{
					ServiceImportPath: "github.com/devimteam/microgen/example/svc",
				}},
			OutFilePath: "grpc_client.go.txt",
		},
		{
			TestName: "GRPC Converter",
			Template: &gRPCEndpointConverterTemplate{
				Info: &GenerationInfo{
					ServiceImportPath:        "github.com/devimteam/microgen/example/svc",
					ServiceImportPackageName: "stringsvc",
				}},
			OutFilePath: "grpc_converters.go.txt",
		},
		{
			TestName: "GRPC Type Converter",
			Template: &stubGRPCTypeConverterTemplate{
				Info: &GenerationInfo{
					ServiceImportPath: "github.com/devimteam/microgen/example/svc",
				}},
			OutFilePath: "grpc_type.go.txt",
		},
	}
	for _, test := range allTemplateTests {
		t.Run(test.TestName, func(t *testing.T) {
			out, err := ioutil.ReadFile(test.OutFilePath)
			if err != nil {
				t.Fatalf("read out file error: %v", err)
			}

			buf := bytes.NewBuffer([]byte{})
			// TODO(nicolai): NewGenerator was commented out in [1]
			// Need to use NewGenUnit now.
			// Also consider testify instead of doing diff heavy-lifting
			// [1] https://github.com/devimteam/microgen/commit/0e094fadf97df0da8c14f5b778a3beea4f646545#diff-338bea067d2a01b69c90f1c032c6a24b

			// TODO(nicolai): Figure out if absOutPath needs to be anything
			absOutPath := ""
			gen := generator.NewGenUnit(test.Template, absOutPath)
			err = gen.Generate()
			if err != nil {
				t.Fatalf("unable to generate: %v", err)
			}
			if buf.String() != string(out[:]) {
				t.Errorf("Got:\n/////////\n%s\n/////////\nExpected:\n/////////\n%s\n/////////", buf.String(), string(out[:]))
				t.Errorf("1: Got(bytes), 2: Expected(bytes):\n/////////\n1: %v\n2: %v\n/////////", buf.Bytes(), out[:])
				x, y, z, line := findDifference(buf.String(), string(out[:]))
				t.Errorf("line:pos:raw %d:%d:%d %d!=%d %v\n`%s`", x+1, y+1, z, buf.Bytes()[z], out[z], len(buf.String()) == len(string(out[:])), line)
			}
		})
	}
}

func findDifference(first, second string) (line int, pos int, raw int, strLine string) {
	for i, sym := range first {
		if first[i] != second[i] {
			return
		}
		if sym == '\n' {
{'fraction_non_alphanumeric': 0.17111988847583642, 'fraction_numerical': 0.006737918215613383, 'mean_word_length': 3.4861907243355916, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2747228', 'n_tokens_mistral': 3564, 'n_tokens_neox': 3088, 'n_words': 644}