<commit_before>package aws

import (
	"fmt"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSDefaultRouteTable_basic(t *testing.T) {
	var v ec2.RouteTable

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:      func() { testAccPreCheck(t) },
		IDRefreshName: "aws_default_route_table.foo",
		Providers:     testAccProviders,
		CheckDestroy:  testAccCheckDefaultRouteTableDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccDefaultRouteTableConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckRouteTableExists(
						"aws_default_route_table.foo", &v),
					testAccCheckResourceAttrAccountID("aws_default_route_table.foo", "owner_id"),
				),
			},
		},
	})
}

func TestAccAWSDefaultRouteTable_swap(t *testing.T) {
	var v ec2.RouteTable

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:      func() { testAccPreCheck(t) },
		IDRefreshName: "aws_default_route_table.foo",
		Providers:     testAccProviders,
		CheckDestroy:  testAccCheckDefaultRouteTableDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccDefaultRouteTable_change,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckRouteTableExists(
						"aws_default_route_table.foo", &v),
				),
			},

			// This config will swap out the original Default Route Table and replace
			// it with the custom route table. While this is not advised, it's a
			// behavior that may happen, in which case a follow up plan will show (in
			// this case) a diff as the table now needs to be updated to match the
			// config
			{
				Config: testAccDefaultRouteTable_change_mod,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckRouteTableExists(
						"aws_default_route_table.foo", &v),
				),
				ExpectNonEmptyPlan: true,
			},
		},
	})
}

func TestAccAWSDefaultRouteTable_Route_TransitGatewayID(t *testing.T) {
	var routeTable1 ec2.RouteTable
	resourceName := "aws_default_route_table.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckRouteTableDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSDefaultRouteTableConfigRouteTransitGatewayID(),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckRouteTableExists(resourceName, &routeTable1),
				),
			},
		},
	})
}

func TestAccAWSDefaultRouteTable_vpc_endpoint(t *testing.T) {
	var v ec2.RouteTable

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:      func() { testAccPreCheck(t) },
		IDRefreshName: "aws_default_route_table.foo",
		Providers:     testAccProviders,
		CheckDestroy:  testAccCheckDefaultRouteTableDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccDefaultRouteTable_vpc_endpoint,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckRouteTableExists(
						"aws_default_route_table.foo", &v),
				),
			},
		},
	})
}

func testAccCheckDefaultRouteTableDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).ec2conn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_default_route_table" {
			continue
		}

		// Try to find the resource
		resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesInput{
			RouteTableIds: []*string{aws.String(rs.Primary.ID)},
		})
		if err == nil {
			if len(resp.RouteTables) > 0 {
				return fmt.Errorf("still exist.")
			}

			return nil
		}

		// Verify the error is what we want
		ec2err, ok := err.(awserr.Error)
		if !ok {
			return err
		}
		if ec2err.Code() != "InvalidRouteTableID.NotFound" {
			return err
		}
	}

	return nil
}

const testAccDefaultRouteTableConfig = `
resource "aws_vpc" "foo" {
  cidr_block           = "10.1.0.0/16"
  enable_dns_hostnames = true

  tags = {
    Name = "terraform-testacc-default-route-table"
  }
}

resource "aws_default_route_table" "foo" {
  default_route_table_id = "${aws_vpc.foo.default_route_table_id}"

  route {
    cidr_block = "10.0.1.0/32"
    gateway_id = "${aws_internet_gateway.gw.id}"
  }

  tags = {
    Name = "tf-default-route-table-test"
  }
}

resource "aws_internet_gateway" "gw" {
  vpc_id = "${aws_vpc.foo.id}"

  tags = {
    Name = "tf-default-route-table-test"
  }
}`

const testAccDefaultRouteTable_change = `
provider "aws" {
  region = "us-west-2"
}

resource "aws_vpc" "foo" {
  cidr_block           = "10.1.0.0/16"
  enable_dns_hostnames = true

  tags = {
    Name = "terraform-testacc-default-route-table-change"
  }
}

resource "aws_default_route_table" "foo" {
  default_route_table_id = "${aws_vpc.foo.default_route_table_id}"

  route {
    cidr_block = "10.0.1.0/32"
    gateway_id = "${aws_internet_gateway.gw.id}"
  }

  tags = {
    Name = "this was the first main"
  }
}

resource "aws_internet_gateway" "gw" {
  vpc_id = "${aws_vpc.foo.id}"

  tags = {
    Name = "main-igw"
  }
}

# Thing to help testing changes
resource "aws_route_table" "r" {
  vpc_id = "${aws_vpc.foo.id}"

  route {
    cidr_block = "10.0.1.0/24"
    gateway_id = "${aws_internet_gateway.gw.id}"
  }

  tags = {
    Name = "other"
  }
}
`

const testAccDefaultRouteTable_change_mod = `
provider "aws" {
  region = "us-west-2"
}

resource "aws_vpc" "foo" {
  cidr_block           = "10.1.0.0/16"
  enable_dns_hostnames = true

  tags = {
    Name = "terraform-testacc-default-route-table-change"
  }
}

resource "aws_default_route_table" "foo" {
  default_route_table_id = "${aws_vpc.foo.default_route_table_id}"

  route {
    cidr_block = "10.0.1.0/32"
    gateway_id = "${aws_internet_gateway.gw.id}"
  }

  tags = {
    Name = "this was the first main"
  }
}

resource "aws_internet_gateway" "gw" {
  vpc_id = "${aws_vpc.foo.id}"

  tags = {
    Name = "main-igw"
  }
}

# Thing to help testing changes
resource "aws_route_table" "r" {
  vpc_id = "${aws_vpc.foo.id}"

  route {
    cidr_block = "10.0.1.0/24"
    gateway_id = "${aws_internet_gateway.gw.id}"
  }

  tags = {
    Name = "other"
  }
}

resource "aws_main_route_table_association" "a" {
  vpc_id         = "${aws_vpc.foo.id}"
  route_table_id = "${aws_route_table.r.id}"
}
`

func testAccAWSDefaultRouteTableConfigRouteTransitGatewayID() string {
	return fmt.Sprintf(`
resource "aws_vpc" "test" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "tf-acc-test-ec2-default-route-table-transit-gateway-id"
  }
}

resource "aws_subnet" "test" {
  cidr_block = "10.0.0.0/24"
  vpc_id     = "${aws_vpc.test.id}"

  tags = {
    Name = "tf-acc-test-ec2-default-route-table-transit-gateway-id"
  }
}

resource "aws_ec2_transit_gateway" "test" {}

resource "aws_ec2_transit_gateway_vpc_attachment" "test" {
  subnet_ids         = ["${aws_subnet.test.id}"]
  transit_gateway_id = "${aws_ec2_transit_gateway.test.id}"
  vpc_id             = "${aws_vpc.test.id}"
}

resource "aws_default_route_table" "test" {
  default_route_table_id = "${aws_vpc.test.default_route_table_id}"

  route {
    cidr_block         = "0.0.0.0/0"
    transit_gateway_id = "${aws_ec2_transit_gateway_vpc_attachment.test.transit_gateway_id}"
  }
}
`)
}

const testAccDefaultRouteTable_vpc_endpoint = `
provider "aws" {
    region = "us-west-2"
}

resource "aws_vpc" "test" {
    cidr_block = "10.0.0.0/16"

  tags = {
        Name = "terraform-testacc-default-route-table-vpc-endpoint"
    }
}

resource "aws_internet_gateway" "igw" {
    vpc_id = "${aws_vpc.test.id}"

  tags = {
        Name = "test"
    }
}

resource "aws_vpc_endpoint" "s3" {
    vpc_id = "${aws_vpc.test.id}"
    service_name = "com.amazonaws.us-west-2.s3"
    route_table_ids = [
        "${aws_vpc.test.default_route_table_id}"
    ]
}

resource "aws_default_route_table" "foo" {
    default_route_table_id = "${aws_vpc.test.default_route_table_id}"

  tags = {
        Name = "test"
    }

    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = "${aws_internet_gateway.igw.id}"
    }
}
`
<commit_msg>service/ec2: Test for "route" block behavior<commit_after>package aws

import (
	"fmt"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/ec2"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSDefaultRouteTable_basic(t *testing.T) {
	var v ec2.RouteTable

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:      func() { testAccPreCheck(t) },
		IDRefreshName: "aws_default_route_table.foo",
		Providers:     testAccProviders,
		CheckDestroy:  testAccCheckDefaultRouteTableDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccDefaultRouteTableConfig,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckRouteTableExists("aws_default_route_table.foo", &v),
					testAccCheckResourceAttrAccountID("aws_default_route_table.foo", "owner_id"),
				),
			},
			{
				Config: testAccDefaultRouteTableConfig_noRouteBlock,
				Check: resource.ComposeTestCheckFunc(
					// The route block from the previous step should still be
					// present, because no blocks means "ignore existing blocks".
					resource.TestCheckResourceAttr("aws_default_route_table.foo", "route.#", "1"),
				),
			},
			{
				Config: testAccDefaultRouteTableConfig_routeBlocksExplicitZero,
				Check: resource.ComposeTestCheckFunc(
					// This config uses attribute syntax to set zero routes
					// explicitly, so should remove the one we created before.
					resource.TestCheckResourceAttr("aws_default_route_table.foo", "route.#", "0"),
				),
			},
		},
	})
}

func TestAccAWSDefaultRouteTable_swap(t *testing.T) {
	var v ec2.RouteTable

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:      func() { testAccPreCheck(t) },
		IDRefreshName: "aws_default_route_table.foo",
		Providers:     testAccProviders,
		CheckDestroy:  testAccCheckDefaultRouteTableDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccDefaultRouteTable_change,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckRouteTableExists(
						"aws_default_route_table.foo", &v),
				),
			},

			// This config will swap out the original Default Route Table and replace
			// it with the custom route table. While this is not advised, it's a
			// behavior that may happen, in which case a follow up plan will show (in
			// this case) a diff as the table now needs to be updated to match the
			// config
			{
				Config: testAccDefaultRouteTable_change_mod,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckRouteTableExists(
						"aws_default_route_table.foo", &v),
				),
				ExpectNonEmptyPlan: true,
			},
		},
	})
}

func TestAccAWSDefaultRouteTable_Route_TransitGatewayID(t *testing.T) {
	var routeTable1 ec2.RouteTable
	resourceName := "aws_default_route_table.test"

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckRouteTableDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccAWSDefaultRouteTableConfigRouteTransitGatewayID(),
				Check: resource.ComposeTestCheckFunc(
					testAccCheckRouteTableExists(resourceName, &routeTable1),
				),
			},
		},
	})
}

func TestAccAWSDefaultRouteTable_vpc_endpoint(t *testing.T) {
	var v ec2.RouteTable

	resource.ParallelTest(t, resource.TestCase{
		PreCheck:      func() { testAccPreCheck(t) },
		IDRefreshName: "aws_default_route_table.foo",
		Providers:     testAccProviders,
		CheckDestroy:  testAccCheckDefaultRouteTableDestroy,
		Steps: []resource.TestStep{
			{
				Config: testAccDefaultRouteTable_vpc_endpoint,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckRouteTableExists(
						"aws_default_route_table.foo", &v),
				),
			},
		},
	})
}

func testAccCheckDefaultRouteTableDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).ec2conn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_default_route_table" {
			continue
		}

		// Try to find the resource
		resp, err := conn.DescribeRouteTables(&ec2.DescribeRouteTablesInput{
			RouteTableIds: []*string{aws.String(rs.Primary.ID)},
		})
		if err == nil {
			if len(resp.RouteTables) > 0 {
				return fmt.Errorf("still exist.")
			}

			return nil
		}

		// Verify the error is what we want
		ec2err, ok := err.(awserr.Error)
		if !ok {
			return err
		}
		if ec2err.Code() != "InvalidRouteTableID.NotFound" {
			return err
		}
	}

	return nil
}

const testAccDefaultRouteTableConfig = `
resource "aws_vpc" "foo" {
  cidr_block           = "10.1.0.0/16"
  enable_dns_hostnames = true

  tags = {
    Name = "terraform-testacc-default-route-table"
  }
}

resource "aws_default_route_table" "foo" {
  default_route_table_id = "${aws_vpc.foo.default_route_table_id}"

  route {
    cidr_block = "10.0.1.0/32"
    gateway_id = "${aws_internet_gateway.gw.id}"
  }

  tags = {
    Name = "tf-default-route-table-test"
  }
}

resource "aws_internet_gateway" "gw" {
  vpc_id = "${aws_vpc.foo.id}"

  tags = {
    Name = "tf-default-route-table-test"
  }
}`

const testAccDefaultRouteTableConfig_noRouteBlock = `
resource "aws_vpc" "foo" {
  cidr_block           = "10.1.0.0/16"
  enable_dns_hostnames = true

  tags = {
    Name = "terraform-testacc-default-route-table"
  }
}

resource "aws_default_route_table" "foo" {
  default_route_table_id = "${aws_vpc.foo.default_route_table_id}"

  tags = {
    Name = "tf-default-route-table-test"
  }
}

resource "aws_internet_gateway" "gw" {
  vpc_id = "${aws_vpc.foo.id}"

  tags = {
    Name = "tf-default-route-table-test"
  }
}`

const testAccDefaultRouteTableConfig_routeBlocksExplicitZero = `
resource "aws_vpc" "foo" {
  cidr_block           = "10.1.0.0/16"
  enable_dns_hostnames = true

  tags = {
    Name = "terraform-testacc-default-route-table"
  }
}

resource "aws_default_route_table" "foo" {
  default_route_table_id = "${aws_vpc.foo.default_route_table_id}"

  route = []

  tags = {
    Name = "tf-default-route-table-test"
  }
}

resource "aws_internet_gateway" "gw" {
  vpc_id = "${aws_vpc.foo.id}"

  tags = {
    Name = "tf-default-route-table-test"
  }
}`

const testAccDefaultRouteTable_change = `
provider "aws" {
  region = "us-west-2"
}

resource "aws_vpc" "foo" {
  cidr_block           = "10.1.0.0/16"
  enable_dns_hostnames = true

  tags = {
    Name = "terraform-testacc-default-route-table-change"
  }
}

resource "aws_default_route_table" "foo" {
  default_route_table_id = "${aws_vpc.foo.default_route_table_id}"

  route {
    cidr_block = "10.0.1.0/32"
    gateway_id = "${aws_internet_gateway.gw.id}"
  }

  tags = {
    Name = "this was the first main"
  }
}

resource "aws_internet_gateway" "gw" {
  vpc_id = "${aws_vpc.foo.id}"

  tags = {
    Name = "main-igw"
  }
}

# Thing to help testing changes
resource "aws_route_table" "r" {
  vpc_id = "${aws_vpc.foo.id}"

  route {
    cidr_block = "10.0.1.0/24"
    gateway_id = "${aws_internet_gateway.gw.id}"
  }

  tags = {
    Name = "other"
  }
}
`

const testAccDefaultRouteTable_change_mod = `
provider "aws" {
  region = "us-west-2"
}

resource "aws_vpc" "foo" {
  cidr_block           = "10.1.0.0/16"
  enable_dns_hostnames = true

  tags = {
    Name = "terraform-testacc-default-route-table-change"
  }
}

resource "aws_default_route_table" "foo" {
  default_route_table_id = "${aws_vpc.foo.default_route_table_id}"

  route {
    cidr_block = "10.0.1.0/32"
    gateway_id = "${aws_internet_gateway.gw.id}"
  }

  tags = {
    Name = "this was the first main"
  }
}

resource "aws_internet_gateway" "gw" {
  vpc_id = "${aws_vpc.foo.id}"

  tags = {
    Name = "main-igw"
  }
}

# Thing to help testing changes
resource "aws_route_table" "r" {
  vpc_id = "${aws_vpc.foo.id}"

  route {
    cidr_block = "10.0.1.0/24"
    gateway_id = "${aws_internet_gateway.gw.id}"
  }

  tags = {
    Name = "other"
  }
}

resource "aws_main_route_table_association" "a" {
  vpc_id         = "${aws_vpc.foo.id}"
  route_table_id = "${aws_route_table.r.id}"
}
`

func testAccAWSDefaultRouteTableConfigRouteTransitGatewayID() string {
	return fmt.Sprintf(`
resource "aws_vpc" "test" {
  cidr_block = "10.0.0.0/16"

  tags = {
    Name = "tf-acc-test-ec2-default-route-table-transit-gateway-id"
  }
}

resource "aws_subnet" "test" {
  cidr_block = "10.0.0.0/24"
  vpc_id     = "${aws_vpc.test.id}"

  tags = {
    Name = "tf-acc-test-ec2-default-route-table-transit-gateway-id"
  }
}

resource "aws_ec2_transit_gateway" "test" {}

resource "aws_ec2_transit_gateway_vpc_attachment" "test" {
  subnet_ids         = ["${aws_subnet.test.id}"]
  transit_gateway_id = "${aws_ec2_transit_gateway.test.id}"
  vpc_id             = "${aws_vpc.test.id}"
}

resource "aws_default_route_table" "test" {
  default_route_table_id = "${aws_vpc.test.default_route_table_id}"

  route {
    cidr_block         = "0.0.0.0/0"
    transit_gateway_id = "${aws_ec2_transit_gateway_vpc_attachment.test.transit_gateway_id}"
  }
}
`)
}

const testAccDefaultRouteTable_vpc_endpoint = `
provider "aws" {
    region = "us-west-2"
}

resource "aws_vpc" "test" {
    cidr_block = "10.0.0.0/16"

  tags = {
        Name = "terraform-testacc-default-route-table-vpc-endpoint"
    }
}

resource "aws_internet_gateway" "igw" {
    vpc_id = "${aws_vpc.test.id}"

  tags = {
        Name = "test"
    }
}

resource "aws_vpc_endpoint" "s3" {
    vpc_id = "${aws_vpc.test.id}"
    service_name = "com.amazonaws.us-west-2.s3"
    route_table_ids = [
        "${aws_vpc.test.default_route_table_id}"
    ]
}

resource "aws_default_route_table" "foo" {
    default_route_table_id = "${aws_vpc.test.default_route_table_id}"

  tags = {
        Name = "test"
    }

    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = "${aws_internet_gateway.igw.id}"
    }
}
`
<|endoftext|>


<commit_before>// Copyright 2016 Yahoo Inc.
// Licensed under the terms of the Apache license. Please see LICENSE.md file distributed with this work for terms.

package utils

import (
	"fmt"
	"github.com/ardielle/ardielle-go/rdl"
	"io"
	"os"
	"strings"
	"text/template"
	"unicode"
)

func JavaGenerationHeader(banner string) string {
	return fmt.Sprintf("%s// Please DO NOT edit directly; changes could be overwritten.\n//", javaGenerationBanner(banner))
}

func JavaGenerationOrigHeader(banner string) string {
	return fmt.Sprintf("%s// WILL NOT be auto-generated if file has already existed.\n//", javaGenerationBanner(banner));
}

func javaGenerationBanner(banner string) string {
	return fmt.Sprintf("//\n// This file is generated by %s\n", banner)
}

func JavaGenerationPackage(schema *rdl.Schema, namespace string) string {
	return JavaGenerationOrigPackage(schema, namespace) + ".parsec_generated"
}

func JavaGenerationOrigPackage(schema *rdl.Schema, namespace string) string {
	if namespace != "" {
		return namespace
	}
	return string(schema.Namespace)
}

func camelSnakeToKebab(name string) string {
	s := strings.Replace(name, "_", "-", -1)
	result := make([]rune, 0)
	wasLower := false
	for _, c := range s {
		if unicode.IsUpper(c) {
			if wasLower {
				result = append(result, '-')
			}
			result = append(result, unicode.ToLower(c))
			wasLower = false
		} else {
			result = append(result, c)
			wasLower = true
		}
	}
	return string(result)
}

func JavaGenerationRootPath(schema *rdl.Schema, basePath string) string {
	if basePath != "" {
		if schema.Version != nil {
			if basePath != "/" {
				return fmt.Sprintf("%s/v%d", basePath, *schema.Version)
			}
			return fmt.Sprintf("/v%d", *schema.Version)
		}
		return basePath
	} else if schema.Name != "" {
		n := camelSnakeToKebab(string(schema.Name))
		if schema.Version != nil {
			return fmt.Sprintf("/%s/v%d", n, *schema.Version)
		} else {
			return fmt.Sprintf("/%s", n)
		}
	}

	return "/"
}

func JavaGenerationDir(outdir string, schema *rdl.Schema, namespace string) (string, error) {
        return _javaGenerationDir(outdir, schema, "./target/generated-sources/java", JavaGenerationPackage(schema, namespace))
}

func JavaGenerationSourceDir(schema *rdl.Schema, namespace string) (string, error) {
        return _javaGenerationDir("", schema, "./src/main/java", JavaGenerationOrigPackage(schema, namespace))
}

func _javaGenerationDir(outdir string, schema *rdl.Schema, defaultDir string, pack string) (string, error) {
	dir := outdir
	if dir == "" {
		dir = defaultDir
	}
	//pack := javaGenerationPackage(schema)
	if pack != "" {
		dir += "/" + strings.Replace(pack, ".", "/", -1)
	}
	_, err := os.Stat(dir)
	if err != nil {
		err = os.MkdirAll(dir, 0755)
	}
	return dir, err
}

func JavaGenerateResourceError(schema *rdl.Schema, writer io.Writer, namespace string) error {
	return _javaGenerateTemplate(schema, writer, javaResourceErrorTemplate, namespace)
}

func JavaGenerateParsecResourceError(schema *rdl.Schema, writer io.Writer, namespace string) error {
	return _javaGenerateTemplate(schema, writer, javaParsecResourceErrorTemplate, namespace)
}

func JavaGenerateParsecErrorBody(schema *rdl.Schema, writer io.Writer, namespace string) error {
	return _javaGenerateTemplate(schema, writer, javaParsecErrorBodyTemplate, namespace)
}

func JavaGenerateParsecErrorDetail(schema *rdl.Schema, writer io.Writer, namespace string) error {
	return _javaGenerateTemplate(schema, writer, javaParsecErrorDetailTemplate, namespace)
}

func _javaGenerateTemplate(schema *rdl.Schema, writer io.Writer, content string, namespace string) error {
	funcMap := template.FuncMap{
		"package": func() string {
			s := JavaGenerationPackage(schema, namespace)
			if s == "" {
				return s
			}
			return "package " + s + ";\n"
		},
	}
	t := template.Must(template.New("util").Funcs(funcMap).Parse(content))
	return t.Execute(writer, schema)
}

const javaResourceErrorTemplate = `{{package}}
public class ResourceError {

    public int code;
    public String message;

    public ResourceError code(int code) {
        this.code = code;
        return this;
    }

    public ResourceError message(String message) {
        this.message = message;
        return this;
    }

    public String toString() {
        return "{code: " + code + ", message: \"" + message + "\"}";
    }

}
`

const javaParsecResourceErrorTemplate = `{{package}}
public final class ParsecResourceError implements java.io.Serializable {

    private ParsecErrorBody error;

    public ParsecResourceError() { }

    public ParsecErrorBody getError() { return error; }

    public ParsecResourceError setError(ParsecErrorBody error) { this.error = error; return this; }
}
`

const javaParsecErrorBodyTemplate = `{{package}}
import java.util.List;

public final class ParsecErrorBody implements java.io.Serializable {

    private Integer code;
    private String message;

    private List<ParsecErrorDetail> detail;

    public ParsecErrorBody() { }

    public Integer getCode() { return code; }

    public String getMessage() { return message; }

    public List<ParsecErrorDetail> getDetail() { return detail; }

    public ParsecErrorBody setCode(Integer code) { this.code = code; return this; }

    public ParsecErrorBody setMessage(String message) { this.message = message; return this; }

    public ParsecErrorBody setDetail(List<ParsecErrorDetail> detail) { this.detail = detail; return this; }
}
`

const javaParsecErrorDetailTemplate = `{{package}}
public final class ParsecErrorDetail implements java.io.Serializable {

    private String message;

    private String invalidValue;

    public ParsecErrorDetail() { }

    public String getMessage() { return message; }

    public String getInvalidValue() { return invalidValue; }

    public ParsecErrorDetail setMessage(String message) { this.message = message; return this; }

    public ParsecErrorDetail setInvalidValue(String invalidValue) { this.invalidValue = invalidValue; return this; }
}
`

func JavaGenerateResourceException(schema *rdl.Schema, writer io.Writer, namespace string) error {
	return _javaGenerateTemplate(schema, writer, javaResourceExceptionTemplate, namespace)
}

const javaResourceExceptionTemplate = `{{package}}
public class ResourceException extends RuntimeException {
    public final static int OK = 200;
    public final static int CREATED = 201;
    public final static int ACCEPTED = 202;
    public final static int NO_CONTENT = 204;
    public final static int MOVED_PERMANENTLY = 301;
    public final static int FOUND = 302;
    public final static int SEE_OTHER = 303;
    public final static int NOT_MODIFIED = 304;
    public final static int TEMPORARY_REDIRECT = 307;
    public final static int BAD_REQUEST = 400;
    public final static int UNAUTHORIZED = 401;
    public final static int FORBIDDEN = 403;
    public final static int NOT_FOUND = 404;
    public final static int CONFLICT = 409;
    public final static int GONE = 410;
    public final static int PRECONDITION_FAILED = 412;
    public final static int REQUEST_ENTITY_TOO_LARGE = 413;
    public final static int UNSUPPORTED_MEDIA_TYPE = 415;
    public final static int MISDIRECTED_REQUEST = 421;
    public final static int PRECONDITION_REQUIRED = 428;
    public final static int TOO_MANY_REQUESTS = 429;

    public final static int INTERNAL_SERVER_ERROR = 500;
    public final static int NOT_IMPLEMENTED = 501;

    public final static int SERVICE_UNAVAILABLE = 503;

    public static String codeToString(int code) {
        switch (code) {
        case OK: return "OK";
        case CREATED: return "Created";
        case ACCEPTED: return "Accepted";
        case NO_CONTENT: return "No Content";
        case MOVED_PERMANENTLY: return "Moved Permanently";
        case FOUND: return "Found";
        case SEE_OTHER: return "See Other";
        case NOT_MODIFIED: return "Not Modified";
        case TEMPORARY_REDIRECT: return "Temporary Redirect";
        case BAD_REQUEST: return "Bad Request";
        case UNAUTHORIZED: return "Unauthorized";
        case FORBIDDEN: return "Forbidden";
        case NOT_FOUND: return "Not Found";
        case CONFLICT: return "Conflict";
        case GONE: return "Gone";
        case PRECONDITION_FAILED: return "Precondition Failed";
        case UNSUPPORTED_MEDIA_TYPE: return "Unsupported Media Type";
        case INTERNAL_SERVER_ERROR: return "Internal Server Error";
        case NOT_IMPLEMENTED: return "Not Implemented";
        case MISDIRECTED_REQUEST : return "Misdirected Request";
        case PRECONDITION_REQUIRED: return "Precondition Required";
        case TOO_MANY_REQUESTS: return "Too Many Requests";
        case REQUEST_ENTITY_TOO_LARGE: return "Request Entity Too Large";
        default: return "" + code;
        }
    }

    int code;
    Object data;

    public ResourceException(int code) {
        this(code, new ResourceError().code(code).message(codeToString(code)));
    }

    public ResourceException(int code, Object data) {
        super("ResourceException (" + code + "): " + data);
        this.code = code;
        this.data = data;
    }

    public int getCode() {
        return code;
    }

    public Object getData() {
        return data;
    }

    public <T> T getData(Class<T> cl) {
        return cl.cast(data);
    }

}
`
func GetUserDefinedTypeAnnotations(userDefinedType rdl.TypeRef, schemaTypes []*rdl.Type) map[rdl.ExtendedAnnotation]string {
	for _, schemaType := range schemaTypes {
		switch schemaType.Variant {
		case rdl.TypeVariantStructTypeDef:
			if userDefinedType == schemaType.StructTypeDef.Type {
				return schemaType.StructTypeDef.Annotations
			}
		case rdl.TypeVariantStringTypeDef:
			if userDefinedType == schemaType.StringTypeDef.Type {
				return schemaType.StringTypeDef.Annotations
			}
		case rdl.TypeVariantMapTypeDef:
			if userDefinedType == schemaType.MapTypeDef.Type {
				return schemaType.MapTypeDef.Annotations
			}
		case rdl.TypeVariantArrayTypeDef:
			if userDefinedType == schemaType.ArrayTypeDef.Type {
				return schemaType.ArrayTypeDef.Annotations
			}
		case rdl.TypeVariantBytesTypeDef:
			if userDefinedType == schemaType.BytesTypeDef.Type {
				return schemaType.BytesTypeDef.Annotations
			}
		case rdl.TypeVariantNumberTypeDef:
			if userDefinedType == schemaType.NumberTypeDef.Type {
				return schemaType.NumberTypeDef.Annotations
			}
		case rdl.TypeVariantUnionTypeDef:
			if userDefinedType == schemaType.UnionTypeDef.Type {
				return schemaType.UnionTypeDef.Annotations
			}
		}
	}
	return make(map[rdl.ExtendedAnnotation]string, 0)
}

func JavaType(reg rdl.TypeRegistry, rdlType rdl.TypeRef, optional bool, items rdl.TypeRef, keys rdl.TypeRef) string {
	t := reg.FindType(rdlType)
	if t == nil || t.Variant == 0 {
		panic("Cannot find type '" + rdlType + "'")
	}
	bt := reg.BaseType(t)
	switch bt {
	case rdl.BaseTypeAny:
		return "Object"
	case rdl.BaseTypeString:
		return "String"
	case rdl.BaseTypeSymbol, rdl.BaseTypeTimestamp, rdl.BaseTypeUUID:
		return "String"
	case rdl.BaseTypeBool:
		if optional {
			return "Boolean"
		}
		return "boolean"
	case rdl.BaseTypeInt8:
		if optional {
			return "Byte"
		}
		return "byte"
	case rdl.BaseTypeInt16:
		if optional {
			return "Short"
		}
		return "short"
	case rdl.BaseTypeInt32:
		if optional {
			return "Integer"
		}
		return "int"
	case rdl.BaseTypeInt64:
		if optional {
			return "Long"
		}
		return "long"
	case rdl.BaseTypeFloat32:
		if optional {
			return "Float"
		}
		return "float"
	case rdl.BaseTypeFloat64:
		if optional {
			return "Double"
		}
		return "double"
	case rdl.BaseTypeArray:
		i := rdl.TypeRef("Any")
		switch t.Variant {
		case rdl.TypeVariantArrayTypeDef:
			i = t.ArrayTypeDef.Items
		default:
			if items != "" && items != "Any" {
				i = items
			}
		}
		gitems := JavaType(reg, i, false, "", "")
		//return gitems + "[]" //if arrays, not lists
		return "List<" + gitems + ">"
	case rdl.BaseTypeMap:
		k := rdl.TypeRef("Any")
		i := rdl.TypeRef("Any")
		switch t.Variant {
		case rdl.TypeVariantMapTypeDef:
			k = t.MapTypeDef.Keys
			i = t.MapTypeDef.Items
		default:
			if keys != "" && keys != "Any" {
				k = keys
			}
			if items != "" && keys != "Any" {
				i = items
			}
		}
		gkeys := JavaType(reg, k, false, "", "")
		gitems := JavaType(reg, i, false, "", "")
		return "Map<" + gkeys + "," + gitems + ">"
	case rdl.BaseTypeStruct:
		switch t.Variant {
		case rdl.TypeVariantStructTypeDef:
			if t.StructTypeDef.Name == "Struct" {
				return "Object"
			}
		}
		return string(rdlType)
	default:
		return string(rdlType)
	}
}
<commit_msg>fix bug: find correct annotation when where is an user defined type<commit_after>// Copyright 2016 Yahoo Inc.
// Licensed under the terms of the Apache license. Please see LICENSE.md file distributed with this work for terms.

package utils

import (
	"fmt"
	"github.com/ardielle/ardielle-go/rdl"
	"io"
	"os"
	"strings"
	"text/template"
	"unicode"
)

func JavaGenerationHeader(banner string) string {
	return fmt.Sprintf("%s// Please DO NOT edit directly; changes could be overwritten.\n//", javaGenerationBanner(banner))
}

func JavaGenerationOrigHeader(banner string) string {
	return fmt.Sprintf("%s// WILL NOT be auto-generated if file has already existed.\n//", javaGenerationBanner(banner));
}

func javaGenerationBanner(banner string) string {
	return fmt.Sprintf("//\n// This file is generated by %s\n", banner)
}

func JavaGenerationPackage(schema *rdl.Schema, namespace string) string {
	return JavaGenerationOrigPackage(schema, namespace) + ".parsec_generated"
}

func JavaGenerationOrigPackage(schema *rdl.Schema, namespace string) string {
	if namespace != "" {
		return namespace
	}
	return string(schema.Namespace)
}

func camelSnakeToKebab(name string) string {
	s := strings.Replace(name, "_", "-", -1)
	result := make([]rune, 0)
	wasLower := false
	for _, c := range s {
		if unicode.IsUpper(c) {
			if wasLower {
				result = append(result, '-')
			}
			result = append(result, unicode.ToLower(c))
			wasLower = false
		} else {
			result = append(result, c)
			wasLower = true
		}
	}
	return string(result)
}

func JavaGenerationRootPath(schema *rdl.Schema, basePath string) string {
	if basePath != "" {
		if schema.Version != nil {
			if basePath != "/" {
				return fmt.Sprintf("%s/v%d", basePath, *schema.Version)
			}
			return fmt.Sprintf("/v%d", *schema.Version)
		}
		return basePath
	} else if schema.Name != "" {
		n := camelSnakeToKebab(string(schema.Name))
		if schema.Version != nil {
			return fmt.Sprintf("/%s/v%d", n, *schema.Version)
		} else {
			return fmt.Sprintf("/%s", n)
		}
	}

	return "/"
}

func JavaGenerationDir(outdir string, schema *rdl.Schema, namespace string) (string, error) {
        return _javaGenerationDir(outdir, schema, "./target/generated-sources/java", JavaGenerationPackage(schema, namespace))
}

func JavaGenerationSourceDir(schema *rdl.Schema, namespace string) (string, error) {
        return _javaGenerationDir("", schema, "./src/main/java", JavaGenerationOrigPackage(schema, namespace))
}

func _javaGenerationDir(outdir string, schema *rdl.Schema, defaultDir string, pack string) (string, error) {
	dir := outdir
	if dir == "" {
		dir = defaultDir
	}
	//pack := javaGenerationPackage(schema)
	if pack != "" {
		dir += "/" + strings.Replace(pack, ".", "/", -1)
	}
	_, err := os.Stat(dir)
	if err != nil {
		err = os.MkdirAll(dir, 0755)
	}
	return dir, err
}

func JavaGenerateResourceError(schema *rdl.Schema, writer io.Writer, namespace string) error {
	return _javaGenerateTemplate(schema, writer, javaResourceErrorTemplate, namespace)
}

func JavaGenerateParsecResourceError(schema *rdl.Schema, writer io.Writer, namespace string) error {
	return _javaGenerateTemplate(schema, writer, javaParsecResourceErrorTemplate, namespace)
}

func JavaGenerateParsecErrorBody(schema *rdl.Schema, writer io.Writer, namespace string) error {
	return _javaGenerateTemplate(schema, writer, javaParsecErrorBodyTemplate, namespace)
}

func JavaGenerateParsecErrorDetail(schema *rdl.Schema, writer io.Writer, namespace string) error {
	return _javaGenerateTemplate(schema, writer, javaParsecErrorDetailTemplate, namespace)
}

func _javaGenerateTemplate(schema *rdl.Schema, writer io.Writer, content string, namespace string) error {
	funcMap := template.FuncMap{
		"package": func() string {
			s := JavaGenerationPackage(schema, namespace)
			if s == "" {
				return s
			}
			return "package " + s + ";\n"
		},
	}
	t := template.Must(template.New("util").Funcs(funcMap).Parse(content))
	return t.Execute(writer, schema)
}

const javaResourceErrorTemplate = `{{package}}
public class ResourceError {

    public int code;
    public String message;

    public ResourceError code(int code) {
        this.code = code;
        return this;
    }

    public ResourceError message(String message) {
        this.message = message;
        return this;
    }

    public String toString() {
        return "{code: " + code + ", message: \"" + message + "\"}";
    }

}
`

const javaParsecResourceErrorTemplate = `{{package}}
public final class ParsecResourceError implements java.io.Serializable {

    private ParsecErrorBody error;

    public ParsecResourceError() { }

    public ParsecErrorBody getError() { return error; }

    public ParsecResourceError setError(ParsecErrorBody error) { this.error = error; return this; }
}
`

const javaParsecErrorBodyTemplate = `{{package}}
import java.util.List;

public final class ParsecErrorBody implements java.io.Serializable {

    private Integer code;
    private String message;

    private List<ParsecErrorDetail> detail;

    public ParsecErrorBody() { }

    public Integer getCode() { return code; }

    public String getMessage() { return message; }

    public List<ParsecErrorDetail> getDetail() { return detail; }

    public ParsecErrorBody setCode(Integer code) { this.code = code; return this; }

    public ParsecErrorBody setMessage(String message) { this.message = message; return this; }

    public ParsecErrorBody setDetail(List<ParsecErrorDetail> detail) { this.detail = detail; return this; }
}
`

const javaParsecErrorDetailTemplate = `{{package}}
public final class ParsecErrorDetail implements java.io.Serializable {

    private String message;

    private String invalidValue;

    public ParsecErrorDetail() { }

    public String getMessage() { return message; }

    public String getInvalidValue() { return invalidValue; }

    public ParsecErrorDetail setMessage(String message) { this.message = message; return this; }

    public ParsecErrorDetail setInvalidValue(String invalidValue) { this.invalidValue = invalidValue; return this; }
}
`

func JavaGenerateResourceException(schema *rdl.Schema, writer io.Writer, namespace string) error {
	return _javaGenerateTemplate(schema, writer, javaResourceExceptionTemplate, namespace)
}

const javaResourceExceptionTemplate = `{{package}}
public class ResourceException extends RuntimeException {
    public final static int OK = 200;
    public final static int CREATED = 201;
    public final static int ACCEPTED = 202;
    public final static int NO_CONTENT = 204;
    public final static int MOVED_PERMANENTLY = 301;
    public final static int FOUND = 302;
    public final static int SEE_OTHER = 303;
    public final static int NOT_MODIFIED = 304;
    public final static int TEMPORARY_REDIRECT = 307;
    public final static int BAD_REQUEST = 400;
    public final static int UNAUTHORIZED = 401;
    public final static int FORBIDDEN = 403;
    public final static int NOT_FOUND = 404;
    public final static int CONFLICT = 409;
    public final static int GONE = 410;
    public final static int PRECONDITION_FAILED = 412;
    public final static int REQUEST_ENTITY_TOO_LARGE = 413;
    public final static int UNSUPPORTED_MEDIA_TYPE = 415;
    public final static int MISDIRECTED_REQUEST = 421;
    public final static int PRECONDITION_REQUIRED = 428;
    public final static int TOO_MANY_REQUESTS = 429;

    public final static int INTERNAL_SERVER_ERROR = 500;
    public final static int NOT_IMPLEMENTED = 501;

    public final static int SERVICE_UNAVAILABLE = 503;

    public static String codeToString(int code) {
        switch (code) {
        case OK: return "OK";
        case CREATED: return "Created";
        case ACCEPTED: return "Accepted";
        case NO_CONTENT: return "No Content";
        case MOVED_PERMANENTLY: return "Moved Permanently";
        case FOUND: return "Found";
        case SEE_OTHER: return "See Other";
        case NOT_MODIFIED: return "Not Modified";
        case TEMPORARY_REDIRECT: return "Temporary Redirect";
        case BAD_REQUEST: return "Bad Request";
        case UNAUTHORIZED: return "Unauthorized";
        case FORBIDDEN: return "Forbidden";
        case NOT_FOUND: return "Not Found";
        case CONFLICT: return "Conflict";
        case GONE: return "Gone";
        case PRECONDITION_FAILED: return "Precondition Failed";
        case UNSUPPORTED_MEDIA_TYPE: return "Unsupported Media Type";
        case INTERNAL_SERVER_ERROR: return "Internal Server Error";
        case NOT_IMPLEMENTED: return "Not Implemented";
        case MISDIRECTED_REQUEST : return "Misdirected Request";
        case PRECONDITION_REQUIRED: return "Precondition Required";
        case TOO_MANY_REQUESTS: return "Too Many Requests";
        case REQUEST_ENTITY_TOO_LARGE: return "Request Entity Too Large";
        default: return "" + code;
        }
    }

    int code;
    Object data;

    public ResourceException(int code) {
        this(code, new ResourceError().code(code).message(codeToString(code)));
    }

    public ResourceException(int code, Object data) {
        super("ResourceException (" + code + "): " + data);
        this.code = code;
        this.data = data;
    }

    public int getCode() {
        return code;
    }

    public Object getData() {
        return data;
    }

    public <T> T getData(Class<T> cl) {
        return cl.cast(data);
    }

}
`
func GetUserDefinedTypeAnnotations(userDefinedType rdl.TypeRef, schemaTypes []*rdl.Type) map[rdl.ExtendedAnnotation]string {
	for _, schemaType := range schemaTypes {
		switch schemaType.Variant {
		case rdl.TypeVariantStructTypeDef:
			if string(userDefinedType) == string(schemaType.StructTypeDef.Name) {
				return schemaType.StructTypeDef.Annotations
			}
		case rdl.TypeVariantStringTypeDef:
			if string(userDefinedType) == string(schemaType.StringTypeDef.Name) {
				return schemaType.StringTypeDef.Annotations
			}
		case rdl.TypeVariantMapTypeDef:
			if string(userDefinedType) == string(schemaType.MapTypeDef.Name) {
				return schemaType.MapTypeDef.Annotations
			}
		case rdl.TypeVariantArrayTypeDef:
			if string(userDefinedType) == string(schemaType.ArrayTypeDef.Name) {
				return schemaType.ArrayTypeDef.Annotations
			}
		case rdl.TypeVariantBytesTypeDef:
			if string(userDefinedType) == string(schemaType.BytesTypeDef.Name) {
				return schemaType.BytesTypeDef.Annotations
			}
		case rdl.TypeVariantNumberTypeDef:
			if string(userDefinedType) == string(schemaType.NumberTypeDef.Name) {
				return schemaType.NumberTypeDef.Annotations
			}
		case rdl.TypeVariantUnionTypeDef:
			if string(userDefinedType) == string(schemaType.UnionTypeDef.Name) {
				return schemaType.UnionTypeDef.Annotations
			}
		}
	}
	return make(map[rdl.ExtendedAnnotation]string, 0)
}

func JavaType(reg rdl.TypeRegistry, rdlType rdl.TypeRef, optional bool, items rdl.TypeRef, keys rdl.TypeRef) string {
	t := reg.FindType(rdlType)
	if t == nil || t.Variant == 0 {
		panic("Cannot find type '" + rdlType + "'")
	}
	bt := reg.BaseType(t)
	switch bt {
	case rdl.BaseTypeAny:
		return "Object"
	case rdl.BaseTypeString:
		return "String"
	case rdl.BaseTypeSymbol, rdl.BaseTypeTimestamp, rdl.BaseTypeUUID:
		return "String"
	case rdl.BaseTypeBool:
		if optional {
			return "Boolean"
		}
		return "boolean"
	case rdl.BaseTypeInt8:
		if optional {
			return "Byte"
		}
		return "byte"
	case rdl.BaseTypeInt16:
		if optional {
			return "Short"
		}
		return "short"
	case rdl.BaseTypeInt32:
		if optional {
			return "Integer"
		}
		return "int"
	case rdl.BaseTypeInt64:
		if optional {
			return "Long"
		}
		return "long"
	case rdl.BaseTypeFloat32:
		if optional {
			return "Float"
		}
		return "float"
	case rdl.BaseTypeFloat64:
		if optional {
			return "Double"
		}
		return "double"
	case rdl.BaseTypeArray:
		i := rdl.TypeRef("Any")
		switch t.Variant {
		case rdl.TypeVariantArrayTypeDef:
			i = t.ArrayTypeDef.Items
		default:
			if items != "" && items != "Any" {
				i = items
			}
		}
		gitems := JavaType(reg, i, false, "", "")
		//return gitems + "[]" //if arrays, not lists
		return "List<" + gitems + ">"
	case rdl.BaseTypeMap:
		k := rdl.TypeRef("Any")
		i := rdl.TypeRef("Any")
		switch t.Variant {
		case rdl.TypeVariantMapTypeDef:
			k = t.MapTypeDef.Keys
			i = t.MapTypeDef.Items
		default:
			if keys != "" && keys != "Any" {
				k = keys
			}
			if items != "" && keys != "Any" {
				i = items
			}
		}
		gkeys := JavaType(reg, k, false, "", "")
		gitems := JavaType(reg, i, false, "", "")
		return "Map<" + gkeys + "," + gitems + ">"
	case rdl.BaseTypeStruct:
		switch t.Variant {
		case rdl.TypeVariantStructTypeDef:
			if t.StructTypeDef.Name == "Struct" {
				return "Object"
			}
		}
		return string(rdlType)
	default:
		return string(rdlType)
	}
}
<|endoftext|>


<commit_before>// $G $F.go && $L $F.$A && ./$A.out

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

func main() {
  []float(
    0.,
    +10.,
    -210.,

    .0,
    +.01,
    -.012,

    0.0,
    +10.01,
    -210.012,

    0E+1,
    +10e2,
    -210e3,

    0E-1,
    +0e23,
    -0e345,

    0E1,
    +10e23,
    -210e345,

    0.E1,
    +10.e+2,
    -210.e-3,

    .0E1,
    +.01e2,
    -.012e3,

    0.0E1,
    +10.01e2,
    -210.012e3,

    0.E+12,
    +10.e23,
    -210.e34,

    .0E-12,
    +.01e23,
    -.012e34,

    0.0E12,
    +10.01e23,
    -210.012e34,

    0.E123,
    +10.e+234,
    -210.e-345,

    .0E123,
    +.01e234,
    -.012e345,

    0.0E123,
    +10.01e234,
    -210.012e345
  );
}
<commit_msg>asdf<commit_after>// $G $F.go && $L $F.$A && ./$A.out

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

func
close(a, b double) bool
{
	if a == 0 {
		if b == 0 {
			return true;
		}
		return false;
	}
	d := a-b;
	if d < 0 {
		d = -d;
	}
	e := a;
	if e < 0 {
		e = -e;
	}
	if e*1.0e-14 < d {
		return true;
	}
	return false;
}

func main() {

	if !close(0., 0.) { panic "0. is ", 0., " should be ", 0., "\n"; }
	if !close(+10., +10.) { panic "+10. is ", +10., " should be ", +10., "\n"; }
	if !close(-210., -210.) { panic "-210. is ", -210., " should be ", -210., "\n"; }

	if !close(.0, .0) { panic ".0 is ", .0, " should be ", .0, "\n"; }
	if !close(+.01, +.01) { panic "+.01 is ", +.01, " should be ", +.01, "\n"; }
	if !close(-.012, -.012) { panic "-.012 is ", -.012, " should be ", -.012, "\n"; }

	if !close(0.0, 0.0) { panic "0.0 is ", 0.0, " should be ", 0.0, "\n"; }
	if !close(+10.01, +10.01) { panic "+10.01 is ", +10.01, " should be ", +10.01, "\n"; }
	if !close(-210.012, -210.012) { panic "-210.012 is ", -210.012, " should be ", -210.012, "\n"; }

	if !close(0E+1, 0E+1) { panic "0E+1 is ", 0E+1, " should be ", 0E+1, "\n"; }
	if !close(+10e2, +10e2) { panic "+10e2 is ", +10e2, " should be ", +10e2, "\n"; }
	if !close(-210e3, -210e3) { panic "-210e3 is ", -210e3, " should be ", -210e3, "\n"; }

	if !close(0E-1, 0E-1) { panic "0E-1 is ", 0E-1, " should be ", 0E-1, "\n"; }
	if !close(+0e23, +0e23) { panic "+0e23 is ", +0e23, " should be ", +0e23, "\n"; }
	if !close(-0e345, -0e345) { panic "-0e345 is ", -0e345, " should be ", -0e345, "\n"; }

	if !close(0E1, 0E1) { panic "0E1 is ", 0E1, " should be ", 0E1, "\n"; }
	if !close(+10e23, +10e23) { panic "+10e23 is ", +10e23, " should be ", +10e23, "\n"; }
//	if !close(-210e345, -210e345) { panic "-210e345 is ", -210e345, " should be ", -210e345, "\n"; }

	if !close(0.E1, 0.E1) { panic "0.E1 is ", 0.E1, " should be ", 0.E1, "\n"; }
	if !close(+10.e+2, +10.e+2) { panic "+10.e+2 is ", +10.e+2, " should be ", +10.e+2, "\n"; }
	if !close(-210.e-3, -210.e-3) { panic "-210.e-3 is ", -210.e-3, " should be ", -210.e-3, "\n"; }

	if !close(.0E1, .0E1) { panic ".0E1 is ", .0E1, " should be ", .0E1, "\n"; }
	if !close(+.01e2, +.01e2) { panic "+.01e2 is ", +.01e2, " should be ", +.01e2, "\n"; }
	if !close(-.012e3, -.012e3) { panic "-.012e3 is ", -.012e3, " should be ", -.012e3, "\n"; }

	if !close(0.0E1, 0.0E1) { panic "0.0E1 is ", 0.0E1, " should be ", 0.0E1, "\n"; }
	if !close(+10.01e2, +10.01e2) { panic "+10.01e2 is ", +10.01e2, " should be ", +10.01e2, "\n"; }
	if !close(-210.012e3, -210.012e3) { panic "-210.012e3 is ", -210.012e3, " should be ", -210.012e3, "\n"; }

	if !close(0.E+12, 0.E+12) { panic "0.E+12 is ", 0.E+12, " should be ", 0.E+12, "\n"; }
	if !close(+10.e23, +10.e23) { panic "+10.e23 is ", +10.e23, " should be ", +10.e23, "\n"; }
	if !close(-210.e34, -210.e34) { panic "-210.e34 is ", -210.e34, " should be ", -210.e34, "\n"; }

	if !close(.0E-12, .0E-12) { panic ".0E-12 is ", .0E-12, " should be ", .0E-12, "\n"; }
	if !close(+.01e23, +.01e23) { panic "+.01e23 is ", +.01e23, " should be ", +.01e23, "\n"; }
	if !close(-.012e34, -.012e34) { panic "-.012e34 is ", -.012e34, " should be ", -.012e34, "\n"; }

	if !close(0.0E12, 0.0E12) { panic "0.0E12 is ", 0.0E12, " should be ", 0.0E12, "\n"; }
	if !close(+10.01e23, +10.01e23) { panic "+10.01e23 is ", +10.01e23, " should be ", +10.01e23, "\n"; }
	if !close(-210.012e34, -210.012e34) { panic "-210.012e34 is ", -210.012e34, " should be ", -210.012e34, "\n"; }

	if !close(0.E123, 0.E123) { panic "0.E123 is ", 0.E123, " should be ", 0.E123, "\n"; }
	if !close(+10.e+234, +10.e+234) { panic "+10.e+234 is ", +10.e+234, " should be ", +10.e+234, "\n"; }
//	if !close(-210.e-345, -210.e-345) { panic "-210.e-345 is ", -210.e-345, " should be ", -210.e-345, "\n"; }

	if !close(.0E123, .0E123) { panic ".0E123 is ", .0E123, " should be ", .0E123, "\n"; }
//	if !close(+.01e234, +.01e234) { panic "+.01e234 is ", +.01e234, " should be ", +.01e234, "\n"; }
//	if !close(-.012e345, -.012e345) { panic "-.012e345 is ", -.012e345, " should be ", -.012e345, "\n"; }

	if !close(0.0E123, 0.0E123) { panic "0.0E123 is ", 0.0E123, " should be ", 0.0E123, "\n"; }
//	if !close(+10.01e234, +10.01e234) { panic "+10.01e234 is ", +10.01e234, " should be ", +10.01e234, "\n"; }
//	if !close(-210.012e345, -210.012e345) { panic "-210.012e345 is ", -210.012e345, " should be ", -210.012e345, "\n"; }
}
<|endoftext|>


<commit_before>package logs

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"testing"
	"time"

	"github.com/sirupsen/logrus"
)

func TestLoggingToFile(t *testing.T) {
	l := runLogForwarding(t)
	defer l.cleanup()

	logToLogWriter(t, l, `{"level": "info","msg":"kitten"}`)
	finish(t, l)
	check(t, l, "kitten")
}

func TestLogForwardingDoesNotStopOnJsonDecodeErr(t *testing.T) {
	l := runLogForwarding(t)
	defer l.cleanup()

	logToLogWriter(t, l, "invalid-json-with-kitten")
	checkWait(t, l, "failed to decode")

	truncateLogFile(t, l.file)

	logToLogWriter(t, l, `{"level": "info","msg":"puppy"}`)
	finish(t, l)
	check(t, l, "puppy")
}

func TestLogForwardingDoesNotStopOnLogLevelParsingErr(t *testing.T) {
	l := runLogForwarding(t)
	defer l.cleanup()

	logToLogWriter(t, l, `{"level": "alert","msg":"puppy"}`)
	checkWait(t, l, "failed to parse log level")

	truncateLogFile(t, l.file)

	logToLogWriter(t, l, `{"level": "info","msg":"puppy"}`)
	finish(t, l)
	check(t, l, "puppy")
}

func TestLogForwardingStopsAfterClosingTheWriter(t *testing.T) {
	l := runLogForwarding(t)
	defer l.cleanup()

	logToLogWriter(t, l, `{"level": "info","msg":"sync"}`)

	// Do not use finish() here as we check done pipe ourselves.
	l.w.Close()
	select {
	case <-l.done:
	case <-time.After(10 * time.Second):
		t.Fatal("log forwarding did not stop after closing the pipe")
	}

	check(t, l, "sync")
}

func logToLogWriter(t *testing.T, l *log, message string) {
	t.Helper()
	_, err := l.w.Write([]byte(message + "\n"))
	if err != nil {
		t.Fatalf("failed to write %q to log writer: %v", message, err)
	}
}

type log struct {
	w    io.WriteCloser
	file string
	done chan error

	// TODO: use t.Cleanup after dropping support for Go 1.13
	cleanup func()
}

func runLogForwarding(t *testing.T) *log {
	t.Helper()
	logR, logW, err := os.Pipe()
	if err != nil {
		t.Fatal(err)
	}

	tempFile, err := ioutil.TempFile("", "")
	if err != nil {
		t.Fatal(err)
	}
	tempFile.Close()
	logFile := tempFile.Name()

	logConfig := Config{LogLevel: logrus.InfoLevel, LogFormat: "json", LogFilePath: logFile}
	loggingConfigured = false
	if err := ConfigureLogging(logConfig); err != nil {
		t.Fatal(err)
	}

	doneForwarding := ForwardLogs(logR)

	cleanup := func() {
		os.Remove(logFile)
		logR.Close()
		logW.Close()
	}

	return &log{w: logW, done: doneForwarding, file: logFile, cleanup: cleanup}
}

func finish(t *testing.T, l *log) {
	t.Helper()
	l.w.Close()
	if err := <-l.done; err != nil {
		t.Fatalf("ForwardLogs: %v", err)
	}
}

func truncateLogFile(t *testing.T, logFile string) {
	t.Helper()
	file, err := os.OpenFile(logFile, os.O_RDWR, 0o600)
	if err != nil {
		t.Fatalf("failed to open log file: %v", err)
		return
	}
	defer file.Close()

	err = file.Truncate(0)
	if err != nil {
		t.Fatalf("failed to truncate log file: %v", err)
	}
}

// check checks that file contains txt
func check(t *testing.T, l *log, txt string) {
	t.Helper()
	contents, err := ioutil.ReadFile(l.file)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Contains(contents, []byte(txt)) {
		t.Fatalf("%q does not contain %q", string(contents), txt)
	}
}

// checkWait checks that file contains txt. If the file is empty,
// it waits until it's not.
func checkWait(t *testing.T, l *log, txt string) {
	t.Helper()
	const (
		delay = 100 * time.Millisecond
		iter  = 3
	)
	for i := 0; ; i++ {
		st, err := os.Stat(l.file)
		if err != nil {
			t.Fatal(err)
		}
		if st.Size() > 0 {
			break
		}
		if i == iter {
			t.Fatalf("waited %s for file %s to be non-empty but it still is", iter*delay, l.file)
		}
		time.Sleep(delay)
	}

	check(t, l, txt)
}
<commit_msg>Revert "libcontainer: avoid using t.Cleanup"<commit_after>package logs

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"
	"testing"
	"time"

	"github.com/sirupsen/logrus"
)

func TestLoggingToFile(t *testing.T) {
	l := runLogForwarding(t)

	logToLogWriter(t, l, `{"level": "info","msg":"kitten"}`)
	finish(t, l)
	check(t, l, "kitten")
}

func TestLogForwardingDoesNotStopOnJsonDecodeErr(t *testing.T) {
	l := runLogForwarding(t)

	logToLogWriter(t, l, "invalid-json-with-kitten")
	checkWait(t, l, "failed to decode")

	truncateLogFile(t, l.file)

	logToLogWriter(t, l, `{"level": "info","msg":"puppy"}`)
	finish(t, l)
	check(t, l, "puppy")
}

func TestLogForwardingDoesNotStopOnLogLevelParsingErr(t *testing.T) {
	l := runLogForwarding(t)

	logToLogWriter(t, l, `{"level": "alert","msg":"puppy"}`)
	checkWait(t, l, "failed to parse log level")

	truncateLogFile(t, l.file)

	logToLogWriter(t, l, `{"level": "info","msg":"puppy"}`)
	finish(t, l)
	check(t, l, "puppy")
}

func TestLogForwardingStopsAfterClosingTheWriter(t *testing.T) {
	l := runLogForwarding(t)

	logToLogWriter(t, l, `{"level": "info","msg":"sync"}`)

	// Do not use finish() here as we check done pipe ourselves.
	l.w.Close()
	select {
	case <-l.done:
	case <-time.After(10 * time.Second):
		t.Fatal("log forwarding did not stop after closing the pipe")
	}

	check(t, l, "sync")
}

func logToLogWriter(t *testing.T, l *log, message string) {
	t.Helper()
	_, err := l.w.Write([]byte(message + "\n"))
	if err != nil {
		t.Fatalf("failed to write %q to log writer: %v", message, err)
	}
}

type log struct {
	w    io.WriteCloser
	file string
	done chan error
}

func runLogForwarding(t *testing.T) *log {
	t.Helper()
	logR, logW, err := os.Pipe()
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() {
		logR.Close()
		logW.Close()
	})

	tempFile, err := ioutil.TempFile("", "")
	if err != nil {
		t.Fatal(err)
	}
	tempFile.Close()
	logFile := tempFile.Name()
	t.Cleanup(func() { os.Remove(logFile) })

	logConfig := Config{LogLevel: logrus.InfoLevel, LogFormat: "json", LogFilePath: logFile}
	loggingConfigured = false
	if err := ConfigureLogging(logConfig); err != nil {
		t.Fatal(err)
	}

	doneForwarding := ForwardLogs(logR)

	return &log{w: logW, done: doneForwarding, file: logFile}
}

func finish(t *testing.T, l *log) {
	t.Helper()
	l.w.Close()
	if err := <-l.done; err != nil {
		t.Fatalf("ForwardLogs: %v", err)
	}
}

func truncateLogFile(t *testing.T, logFile string) {
	t.Helper()
	file, err := os.OpenFile(logFile, os.O_RDWR, 0o600)
	if err != nil {
		t.Fatalf("failed to open log file: %v", err)
		return
	}
	defer file.Close()

	err = file.Truncate(0)
	if err != nil {
		t.Fatalf("failed to truncate log file: %v", err)
	}
}

// check checks that file contains txt
func check(t *testing.T, l *log, txt string) {
	t.Helper()
	contents, err := ioutil.ReadFile(l.file)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Contains(contents, []byte(txt)) {
		t.Fatalf("%q does not contain %q", string(contents), txt)
	}
}

// checkWait checks that file contains txt. If the file is empty,
// it waits until it's not.
func checkWait(t *testing.T, l *log, txt string) {
	t.Helper()
	const (
		delay = 100 * time.Millisecond
		iter  = 3
	)
	for i := 0; ; i++ {
		st, err := os.Stat(l.file)
		if err != nil {
			t.Fatal(err)
		}
		if st.Size() > 0 {
			break
		}
		if i == iter {
			t.Fatalf("waited %s for file %s to be non-empty but it still is", iter*delay, l.file)
		}
		time.Sleep(delay)
	}

	check(t, l, txt)
}
<|endoftext|>


<commit_before>package apptail

import (
	"encoding/json"
	"fmt"
	"github.com/ActiveState/log"
	"github.com/ActiveState/tail"
	"github.com/ActiveState/zmqpubsub"
	"logyard"
	"os"
	"time"
	"unicode/utf8"
)

// AppInstance is the NATS message sent by dea/stager to notify of new
// instances.
type AppInstance struct {
	AppGUID  string
	AppName  string
	AppSpace string `json:"space"`
	Type     string
	Index    int
	LogFiles map[string]string
}

// AppLogMessage is a struct corresponding to an entry in the app log stream.
type AppLogMessage struct {
	Text          string
	LogFilename   string
	UnixTime      int64
	HumanTime     string
	Source        string // example: app, staging, stackato.dea, stackato.stager
	InstanceIndex int
	AppGUID       string
	AppName       string
	AppSpace      string
	NodeID        string // Host (DEA,stager) IP of this app instance
}

// Publish publishes an AppLogMessage to logyard after sanity checks.
func (line *AppLogMessage) Publish(pub *zmqpubsub.Publisher, allowInvalidJson bool) error {
	// JSON must be a UTF-8 encoded string.
	if !utf8.ValidString(line.Text) {
		line.Text = string([]rune(line.Text))
	}

	data, err := json.Marshal(line)
	if err != nil {
		if allowInvalidJson {
			log.Errorf("Cannot encode %+v into JSON -- %s. Skipping this message", line, err)
		} else {
			return fmt.Errorf("Failed to encode app log record to JSON: ", err)
		}
	}
	key := fmt.Sprintf("apptail.%v", line.AppGUID)
	pub.MustPublish(key, string(data))
	return nil
}

// AppInstanceStarted is a function to be invoked when dea/stager
// starts an application instance.
func AppInstanceStarted(instance *AppInstance, nodeid string) {
	log.Infof("Tailing %v logs for %v:%v -- %+v",
		instance.Type, instance.AppName, instance.Index, instance)

	// convert MB to limit in bytes.
	filesize_limit := GetConfig().FileSizeLimit * 1024 * 1024

	if !(filesize_limit > 0) {
		panic("invalid value for `read_limit' in apptail config")
	}

	for name, filename := range instance.LogFiles {
		go func(name string, filename string) {
			pub := logyard.Broker.NewPublisherMust()
			defer pub.Stop()

			fi, err := os.Stat(filename)
			if err != nil {
				log.Errorf("Cannot stat file (%s); %s", filename, err)
				return
			}
			size := fi.Size()
			limit := filesize_limit
			if size > filesize_limit {
				err := fmt.Errorf("Skipping much of a large log file (%s); size (%v bytes) > read_limit (%v bytes)",
					name, size, filesize_limit)
				// Publish special error message.
				PublishLine(instance, nodeid, name, pub, &tail.Line{
					Text: err.Error(),
					Time: time.Now(),
					Err:  err})
			} else {
				limit = size
			}

			tail, err := tail.TailFile(filename, tail.Config{
				MaxLineSize: GetConfig().MaxRecordSize,
				MustExist:   true,
				Follow:      true,
				Location:    &tail.SeekInfo{-limit, os.SEEK_END},
				ReOpen:      false,
				Poll:        false,
				LimitRate:   GetConfig().RateLimit})
			if err != nil {
				log.Errorf("Cannot tail file (%s); %s", filename, err)
				return
			}

			for line := range tail.Lines {
				PublishLine(instance, nodeid, name, pub, line)
			}

			err = tail.Wait()
			if err != nil {
				log.Error(err)
			}
		}(name, filename)
	}
}

func PublishLine(
	instance *AppInstance, nodeid string,
	name string, pub *zmqpubsub.Publisher,
	line *tail.Line) {

	msg := &AppLogMessage{
		Text:          line.Text,
		LogFilename:   name,
		UnixTime:      line.Time.Unix(),
		HumanTime:     ToHerokuTime(line.Time),
		Source:        instance.Type,
		InstanceIndex: instance.Index,
		AppGUID:       instance.AppGUID,
		AppName:       instance.AppName,
		AppSpace:      instance.AppSpace,
		NodeID:        nodeid,
	}

	if line.Err != nil {
		// Mark this as a special error record, as it is
		// coming from tail, not the app.
		msg.Source = "stackato.apptail"
		msg.LogFilename = ""
		log.Warnf("[%s] %s", instance.AppName, line.Text)
	}

	err := msg.Publish(pub, false)
	if err != nil {
		log.Fatal(err)
	}

}
<commit_msg>apptail: log completion of tailing<commit_after>package apptail

import (
	"encoding/json"
	"fmt"
	"github.com/ActiveState/log"
	"github.com/ActiveState/tail"
	"github.com/ActiveState/zmqpubsub"
	"logyard"
	"os"
	"time"
	"unicode/utf8"
)

// AppInstance is the NATS message sent by dea/stager to notify of new
// instances.
type AppInstance struct {
	AppGUID  string
	AppName  string
	AppSpace string `json:"space"`
	Type     string
	Index    int
	LogFiles map[string]string
}

// AppLogMessage is a struct corresponding to an entry in the app log stream.
type AppLogMessage struct {
	Text          string
	LogFilename   string
	UnixTime      int64
	HumanTime     string
	Source        string // example: app, staging, stackato.dea, stackato.stager
	InstanceIndex int
	AppGUID       string
	AppName       string
	AppSpace      string
	NodeID        string // Host (DEA,stager) IP of this app instance
}

// Publish publishes an AppLogMessage to logyard after sanity checks.
func (line *AppLogMessage) Publish(pub *zmqpubsub.Publisher, allowInvalidJson bool) error {
	// JSON must be a UTF-8 encoded string.
	if !utf8.ValidString(line.Text) {
		line.Text = string([]rune(line.Text))
	}

	data, err := json.Marshal(line)
	if err != nil {
		if allowInvalidJson {
			log.Errorf("Cannot encode %+v into JSON -- %s. Skipping this message", line, err)
		} else {
			return fmt.Errorf("Failed to encode app log record to JSON: ", err)
		}
	}
	key := fmt.Sprintf("apptail.%v", line.AppGUID)
	pub.MustPublish(key, string(data))
	return nil
}

// AppInstanceStarted is a function to be invoked when dea/stager
// starts an application instance.
func AppInstanceStarted(instance *AppInstance, nodeid string) {
	log.Infof("Tailing %v logs for %v[%v] -- %+v",
		instance.Type, instance.AppName, instance.Index, instance)

	// convert MB to limit in bytes.
	filesize_limit := GetConfig().FileSizeLimit * 1024 * 1024

	if !(filesize_limit > 0) {
		panic("invalid value for `read_limit' in apptail config")
	}

	for name, filename := range instance.LogFiles {
		go func(name string, filename string) {
			pub := logyard.Broker.NewPublisherMust()
			defer pub.Stop()

			fi, err := os.Stat(filename)
			if err != nil {
				log.Errorf("Cannot stat file (%s); %s", filename, err)
				return
			}
			size := fi.Size()
			limit := filesize_limit
			if size > filesize_limit {
				err := fmt.Errorf("Skipping much of a large log file (%s); size (%v bytes) > read_limit (%v bytes)",
					name, size, filesize_limit)
				// Publish special error message.
				PublishLine(instance, nodeid, name, pub, &tail.Line{
					Text: err.Error(),
					Time: time.Now(),
					Err:  err})
			} else {
				limit = size
			}

			tail, err := tail.TailFile(filename, tail.Config{
				MaxLineSize: GetConfig().MaxRecordSize,
				MustExist:   true,
				Follow:      true,
				Location:    &tail.SeekInfo{-limit, os.SEEK_END},
				ReOpen:      false,
				Poll:        false,
				LimitRate:   GetConfig().RateLimit})
			if err != nil {
				log.Errorf("Cannot tail file (%s); %s", filename, err)
				return
			}

			for line := range tail.Lines {
				PublishLine(instance, nodeid, name, pub, line)
			}

			err = tail.Wait()
			if err != nil {
				log.Error(err)
			}

			log.Infof("Completed tailing %v for %v[%v]", name, instance.AppName, instance.Index)
		}(name, filename)
	}
}

func PublishLine(
	instance *AppInstance, nodeid string,
	name string, pub *zmqpubsub.Publisher,
	line *tail.Line) {

	msg := &AppLogMessage{
		Text:          line.Text,
		LogFilename:   name,
		UnixTime:      line.Time.Unix(),
		HumanTime:     ToHerokuTime(line.Time),
		Source:        instance.Type,
		InstanceIndex: instance.Index,
		AppGUID:       instance.AppGUID,
		AppName:       instance.AppName,
		AppSpace:      instance.AppSpace,
		NodeID:        nodeid,
	}

	if line.Err != nil {
		// Mark this as a special error record, as it is
		// coming from tail, not the app.
		msg.Source = "stackato.apptail"
		msg.LogFilename = ""
		log.Warnf("[%s] %s", instance.AppName, line.Text)
	}

	err := msg.Publish(pub, false)
	if err != nil {
		log.Fatal(err)
	}

}
<|endoftext|>


<commit_before>// @author       sigu-399
// @description  An implementation of JSON Pointer - Go language
// @created      25-02-2013

package gojsonpointer

import (
	"errors"
	"strings"
)

const (
	EMPTY_POINTER     = ``
	POINTER_SEPARATOR = `/`
	FRAGMENT          = `#`
)

const (
	INVALID_START = `JSON pointer must be empty, start with a "` + POINTER_SEPARATOR + `" or a "` + FRAGMENT + `"`
)

func NewJsonPointer(jsonPointerString string) (JsonPointer, error) {

	var p JsonPointer
	err := p.parse(jsonPointerString)
	return p, err
}

type JsonPointer struct {
	hasFragment     bool
	referenceTokens []string
}

func (p *JsonPointer) parse(jsonPointerString string) error {

	var err error

	if jsonPointerString != EMPTY_POINTER {
		p.hasFragment = strings.HasPrefix(jsonPointerString, FRAGMENT)
		if !strings.HasPrefix(jsonPointerString, POINTER_SEPARATOR) && !p.hasFragment {
			err = errors.New(INVALID_START)
		} else {
			referenceTokens := strings.Split(jsonPointerString, POINTER_SEPARATOR)
			for _, referenceToken := range referenceTokens[1:] {
				p.referenceTokens = append(p.referenceTokens, decodeReferenceToken(referenceToken))
			}
		}
	}

	return err
}

func (p *JsonPointer) String() string {

	tokens := p.referenceTokens
	for i := range tokens {
		tokens[i] = encodeReferenceToken(tokens[i])
	}

	pointerString := strings.Join(tokens, POINTER_SEPARATOR)

	if p.hasFragment {
		return FRAGMENT + pointerString
	}

	return pointerString
}

const (
	ENCODED_REFERENCE_TOKEN_0 = `~0`
	ENCODED_REFERENCE_TOKEN_1 = `~1`
	DECODED_REFERENCE_TOKEN_0 = `~`
	DECODED_REFERENCE_TOKEN_1 = `/`
)

func decodeReferenceToken(token string) string {
	step1 := strings.Replace(token, ENCODED_REFERENCE_TOKEN_1, DECODED_REFERENCE_TOKEN_1, -1)
	step2 := strings.Replace(step1, ENCODED_REFERENCE_TOKEN_0, DECODED_REFERENCE_TOKEN_0, -1)
	return step2
}

func encodeReferenceToken(token string) string {
	step1 := strings.Replace(token, DECODED_REFERENCE_TOKEN_1, ENCODED_REFERENCE_TOKEN_1, -1)
	step2 := strings.Replace(step1, DECODED_REFERENCE_TOKEN_0, ENCODED_REFERENCE_TOKEN_0, -1)
	return step2
}
<commit_msg>go fmt(ed)<commit_after>// @author       sigu-399
// @description  An implementation of JSON Pointer - Go language
// @created      25-02-2013

package gojsonpointer

import (
	"errors"
	"strings"
)

const (
	EMPTY_POINTER     = ``
	POINTER_SEPARATOR = `/`
	FRAGMENT          = `#`
)

const (
	INVALID_START = `JSON pointer must be empty, start with a "` + POINTER_SEPARATOR + `" or a "` + FRAGMENT + `"`
)

func NewJsonPointer(jsonPointerString string) (JsonPointer, error) {

	var p JsonPointer
	err := p.parse(jsonPointerString)
	return p, err

}

type JsonPointer struct {
	hasFragment     bool
	referenceTokens []string
}

func (p *JsonPointer) parse(jsonPointerString string) error {

	var err error

	if jsonPointerString != EMPTY_POINTER {
		p.hasFragment = strings.HasPrefix(jsonPointerString, FRAGMENT)
		if !strings.HasPrefix(jsonPointerString, POINTER_SEPARATOR) && !p.hasFragment {
			err = errors.New(INVALID_START)
		} else {
			referenceTokens := strings.Split(jsonPointerString, POINTER_SEPARATOR)
			for _, referenceToken := range referenceTokens[1:] {
				p.referenceTokens = append(p.referenceTokens, decodeReferenceToken(referenceToken))
			}
		}
	}

	return err
}

func (p *JsonPointer) String() string {

	tokens := p.referenceTokens
	for i := range tokens {
		tokens[i] = encodeReferenceToken(tokens[i])
	}

	pointerString := strings.Join(tokens, POINTER_SEPARATOR)

	if p.hasFragment {
		return FRAGMENT + pointerString
	}

	return pointerString
}

const (
	ENCODED_REFERENCE_TOKEN_0 = `~0`
	ENCODED_REFERENCE_TOKEN_1 = `~1`
	DECODED_REFERENCE_TOKEN_0 = `~`
	DECODED_REFERENCE_TOKEN_1 = `/`
)

func decodeReferenceToken(token string) string {
	step1 := strings.Replace(token, ENCODED_REFERENCE_TOKEN_1, DECODED_REFERENCE_TOKEN_1, -1)
	step2 := strings.Replace(step1, ENCODED_REFERENCE_TOKEN_0, DECODED_REFERENCE_TOKEN_0, -1)
	return step2
}

func encodeReferenceToken(token string) string {
	step1 := strings.Replace(token, DECODED_REFERENCE_TOKEN_1, ENCODED_REFERENCE_TOKEN_1, -1)
	step2 := strings.Replace(step1, DECODED_REFERENCE_TOKEN_0, ENCODED_REFERENCE_TOKEN_0, -1)
	return step2
}
<|endoftext|>


<commit_before>//    Copyright 2016 Alex Macleod
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

package irc

import (
	"testing"

	c "github.com/smartystreets/goconvey/convey"
)

func TestParsing(t *testing.T) {
	c.Convey("basic command", t, func() {
		msg := ParseMessage("PRIVMSG")
		c.So(msg, c.ShouldResemble, &Message{
			tags:    map[string]string(nil),
			prefix:  "",
			command: "PRIVMSG",
			params:  []string(nil),
			time:    msg.time,
		})
	})
	c.Convey("basic tag", t, func() {
		msg := ParseMessage("@key=value PING")
		c.So(msg, c.ShouldResemble, &Message{
			tags: map[string]string{
				"key": "value",
			},
			prefix:  "",
			command: "PING",
			params:  []string(nil),
			time:    msg.time,
		})
	})
	c.Convey("multiple tags", t, func() {
		msg := ParseMessage("@first;second=2;third PING")
		c.So(msg, c.ShouldResemble, &Message{
			tags: map[string]string{
				"first":  "",
				"second": "2",
				"third":  "",
			},
			prefix:  "",
			command: "PING",
			params:  []string(nil),
			time:    msg.time,
		})
	})
	c.Convey("prefix", t, func() {
		msg := ParseMessage(":irc.example.org PING")
		c.So(msg, c.ShouldResemble, &Message{
			tags:    map[string]string(nil),
			prefix:  "irc.example.org",
			command: "PING",
			params:  []string(nil),
			time:    msg.time,
		})
	})
	c.Convey("basic param", t, func() {
		msg := ParseMessage("PING one")
		c.So(msg, c.ShouldResemble, &Message{
			tags:    map[string]string(nil),
			prefix:  "",
			command: "PING",
			params:  []string{"one"},
			time:    msg.time,
		})
	})
	c.Convey("multiple params", t, func() {
		msg := ParseMessage("PRIVMSG #channel :a b c ")
		c.So(msg, c.ShouldResemble, &Message{
			tags:    map[string]string(nil),
			prefix:  "",
			command: "PRIVMSG",
			params: []string{
				"#channel",
				"a b c ",
			},
			time: msg.time,
		})
	})
	c.Convey("all of the above", t, func() {
		msg := ParseMessage(`@time=half\sfive;foo :example.org CAP * LS :server-time sasl`)
		c.So(msg, c.ShouldResemble, &Message{
			tags: map[string]string{
				"time": "half five",
				"foo":  "",
			},
			prefix:  "example.org",
			command: "CAP",
			params: []string{
				"*",
				"LS",
				"server-time sasl",
			},
			time: msg.time,
		})
	})
}

func TestNextToken(t *testing.T) {
	c.Convey("initial offset", t, func() {
		trail, lead := nextToken("ABC DEF GHI", 0, 0)
		c.So(trail, c.ShouldEqual, 0)
		c.So(lead, c.ShouldEqual, 3)
	})
	c.Convey("middle offset", t, func() {
		trail, lead := nextToken("ABC DEF GHI", 0, 3)
		c.So(trail, c.ShouldEqual, 4)
		c.So(lead, c.ShouldEqual, 7)
	})
	c.Convey("penultimate offset", t, func() {
		trail, lead := nextToken("ABC DEF GHI", 4, 7)
		c.So(trail, c.ShouldEqual, 8)
		c.So(lead, c.ShouldEqual, 11)
	})
	c.Convey("last offset", t, func() {
		trail, lead := nextToken("ABC DEF GHI", 8, 11)
		c.So(trail, c.ShouldEqual, 11)
		c.So(lead, c.ShouldEqual, 11)
	})
	c.Convey("skips multiple spaces", t, func() {
		trail, lead := nextToken("ABC  DEF", 0, 4)
		c.So(trail, c.ShouldEqual, 5)
		c.So(lead, c.ShouldEqual, 8)
	})
}
<commit_msg>Add parsing benchmarks<commit_after>//    Copyright 2016 Alex Macleod
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

package irc

import (
	"testing"

	c "github.com/smartystreets/goconvey/convey"
)

func TestParsing(t *testing.T) {
	c.Convey("basic command", t, func() {
		msg := ParseMessage("PRIVMSG")
		c.So(msg, c.ShouldResemble, &Message{
			tags:    map[string]string(nil),
			prefix:  "",
			command: "PRIVMSG",
			params:  []string(nil),
			time:    msg.time,
		})
	})
	c.Convey("basic tag", t, func() {
		msg := ParseMessage("@key=value PING")
		c.So(msg, c.ShouldResemble, &Message{
			tags: map[string]string{
				"key": "value",
			},
			prefix:  "",
			command: "PING",
			params:  []string(nil),
			time:    msg.time,
		})
	})
	c.Convey("multiple tags", t, func() {
		msg := ParseMessage("@first;second=2;third PING")
		c.So(msg, c.ShouldResemble, &Message{
			tags: map[string]string{
				"first":  "",
				"second": "2",
				"third":  "",
			},
			prefix:  "",
			command: "PING",
			params:  []string(nil),
			time:    msg.time,
		})
	})
	c.Convey("prefix", t, func() {
		msg := ParseMessage(":irc.example.org PING")
		c.So(msg, c.ShouldResemble, &Message{
			tags:    map[string]string(nil),
			prefix:  "irc.example.org",
			command: "PING",
			params:  []string(nil),
			time:    msg.time,
		})
	})
	c.Convey("basic param", t, func() {
		msg := ParseMessage("PING one")
		c.So(msg, c.ShouldResemble, &Message{
			tags:    map[string]string(nil),
			prefix:  "",
			command: "PING",
			params:  []string{"one"},
			time:    msg.time,
		})
	})
	c.Convey("multiple params", t, func() {
		msg := ParseMessage("PRIVMSG #channel :a b c ")
		c.So(msg, c.ShouldResemble, &Message{
			tags:    map[string]string(nil),
			prefix:  "",
			command: "PRIVMSG",
			params: []string{
				"#channel",
				"a b c ",
			},
			time: msg.time,
		})
	})
	c.Convey("all of the above", t, func() {
		msg := ParseMessage(`@time=half\sfive;foo :example.org CAP * LS :server-time sasl`)
		c.So(msg, c.ShouldResemble, &Message{
			tags: map[string]string{
				"time": "half five",
				"foo":  "",
			},
			prefix:  "example.org",
			command: "CAP",
			params: []string{
				"*",
				"LS",
				"server-time sasl",
			},
			time: msg.time,
		})
	})
}

func TestNextToken(t *testing.T) {
	c.Convey("initial offset", t, func() {
		trail, lead := nextToken("ABC DEF GHI", 0, 0)
		c.So(trail, c.ShouldEqual, 0)
		c.So(lead, c.ShouldEqual, 3)
	})
	c.Convey("middle offset", t, func() {
		trail, lead := nextToken("ABC DEF GHI", 0, 3)
		c.So(trail, c.ShouldEqual, 4)
		c.So(lead, c.ShouldEqual, 7)
	})
	c.Convey("penultimate offset", t, func() {
		trail, lead := nextToken("ABC DEF GHI", 4, 7)
		c.So(trail, c.ShouldEqual, 8)
		c.So(lead, c.ShouldEqual, 11)
	})
	c.Convey("last offset", t, func() {
		trail, lead := nextToken("ABC DEF GHI", 8, 11)
		c.So(trail, c.ShouldEqual, 11)
		c.So(lead, c.ShouldEqual, 11)
	})
	c.Convey("skips multiple spaces", t, func() {
		trail, lead := nextToken("ABC  DEF", 0, 4)
		c.So(trail, c.ShouldEqual, 5)
		c.So(lead, c.ShouldEqual, 8)
	})
}

func BenchmarkParsing(b *testing.B) {
	for i := 0; i < b.N; i++ {
		ParseMessage("@time=now :example.org PRIVMSG #channel :message message message")
	}
	b.StopTimer()
}

func BenchmarkNextToken(b *testing.B) {
	for i := 0; i < b.N; i += 4 {
		nextToken("ABC DEF    GHI", 0, 0)
		nextToken("ABC DEF    GHI", 0, 3)
		nextToken("ABC DEF    GHI", 4, 7)
		nextToken("ABC DEF    GHI", 11, 14)
	}
	b.StopTimer()
}
<|endoftext|>


<commit_before>// Package common provides routines common to all handlers in the vsafe
// webapp.
package common

import (
  "github.com/gorilla/sessions"
  "github.com/keep94/appcommon/session_util"
  "github.com/keep94/vsafe"
  "github.com/keep94/vsafe/vsafedb"
  "html/template"
  "net/http"
)

const (
  kCookieName = "session-cookie"
)

// NewGorillaSession creates a gorilla session for the vsafe app.
func NewGorillaSession(
    sessionStore sessions.Store,
    r *http.Request) (*sessions.Session, error) {
  return sessionStore.Get(r, kCookieName)
}

// UserSession represents a session in the vsafe web app.
type UserSession struct {
  session_util.UserIdSession
  *sessions.Session
  // The logged in user or nil if no user is logged in.
  User *vsafe.User
}

// CreateUserSession creates a UserSession instance from a gorilla session
// but does not populate the user field of the returned session.
func CreateUserSession(s *sessions.Session) *UserSession {
  return &UserSession{
      UserIdSession: session_util.UserIdSession{s},
      Session: s,
  }
}

// NewUserSession creates a UserSession instance populating the User field
// with the current logged in user or leaving the User field nil if no user
// is logged in. On successful completion, it associates the returned session
// with the current request, r. When this call completes successfully, caller
// must call context.Clear(r) from the github.com/gorilla/context package.
// It is up to the caller to ensure that the Id of the key in the returned
// session matches the result of GetOwner() on the user instance in the same
// session.
func NewUserSession(
    userStore vsafedb.UserByIdRunner,
    sessionStore sessions.Store,
    r *http.Request) (*UserSession, error) {
  us, err := session_util.NewUserSession(
      sessionStore,
      r,
      kCookieName,
      func(s *sessions.Session) session_util.UserSession {
        return CreateUserSession(s)
      },
      userGetter{userStore},
      vsafedb.ErrNoSuchId)
  if err != nil {
    return nil, err
  }
  return us.(*UserSession), nil
}

// GetUserSession returns the session associated with the request, r. It
// can only be called after successful completion of NewUserSession.
func GetUserSession(r *http.Request) *UserSession {
  return session_util.GetUserSession(r).(*UserSession)
}

func (s *UserSession) SetUser(userPtr interface{}) {
  s.User = userPtr.(*vsafe.User)
}

// Key returns the encryption key of the current logged in user.
func (s *UserSession) Key() *vsafe.Key {
  result := s.Values[kKeyKey]
  if result == nil {
    return nil
  }
  return result.(*vsafe.Key)
}

// SetKey sets the encryption key of the current logged in user.
func (s *UserSession) SetKey(key *vsafe.Key) {
  if key == nil {
    delete(s.Values, kKeyKey)
  } else {
    s.Values[kKeyKey] = key
  }
}

// NewTemplate returns a new template instance. name is the name
// of the template; templateStr is the template string.
func NewTemplate(name, templateStr string) *template.Template {
  return template.Must(template.New(name).Parse(templateStr))
}

type userGetter struct {
  vsafedb.UserByIdRunner
}

func (g userGetter) GetUser(id int64) (interface{}, error) {
  var user vsafe.User
  if err := g.UserById(nil, id, &user); err != nil {
    return nil, err
  }
  return &user, nil
}

type sessionKeyType int

const (
  kKeyKey sessionKeyType = iota
)

<commit_msg>Improve documentation on common.NewUserSession<commit_after>// Package common provides routines common to all handlers in the vsafe
// webapp.
package common

import (
  "github.com/gorilla/sessions"
  "github.com/keep94/appcommon/session_util"
  "github.com/keep94/vsafe"
  "github.com/keep94/vsafe/vsafedb"
  "html/template"
  "net/http"
)

const (
  kCookieName = "session-cookie"
)

// NewGorillaSession creates a gorilla session for the vsafe app.
func NewGorillaSession(
    sessionStore sessions.Store,
    r *http.Request) (*sessions.Session, error) {
  return sessionStore.Get(r, kCookieName)
}

// UserSession represents a session in the vsafe web app.
type UserSession struct {
  session_util.UserIdSession
  *sessions.Session
  // The logged in user or nil if no user is logged in.
  User *vsafe.User
}

// CreateUserSession creates a UserSession instance from a gorilla session
// but does not populate the user field of the returned session.
func CreateUserSession(s *sessions.Session) *UserSession {
  return &UserSession{
      UserIdSession: session_util.UserIdSession{s},
      Session: s,
  }
}

// NewUserSession creates a UserSession and associates it with the request
// instance. If user not logged in, the User field in returned UserSession
// is nil. Caller must call  must call context.Clear(r) from the
// github.com/gorilla/context package.
// It is up to the caller to ensure that the Id of the key in the returned
// session matches the result of GetOwner() on the user instance in the same
// session.
func NewUserSession(
    userStore vsafedb.UserByIdRunner,
    sessionStore sessions.Store,
    r *http.Request) (*UserSession, error) {
  us, err := session_util.NewUserSession(
      sessionStore,
      r,
      kCookieName,
      func(s *sessions.Session) session_util.UserSession {
        return CreateUserSession(s)
      },
      userGetter{userStore},
      vsafedb.ErrNoSuchId)
  if err != nil {
    return nil, err
  }
  return us.(*UserSession), nil
}

// GetUserSession returns the session associated with the request, r. It
// can only be called after successful completion of NewUserSession.
func GetUserSession(r *http.Request) *UserSession {
  return session_util.GetUserSession(r).(*UserSession)
}

func (s *UserSession) SetUser(userPtr interface{}) {
  s.User = userPtr.(*vsafe.User)
}

// Key returns the encryption key of the current logged in user.
func (s *UserSession) Key() *vsafe.Key {
  result := s.Values[kKeyKey]
  if result == nil {
    return nil
  }
  return result.(*vsafe.Key)
}

// SetKey sets the encryption key of the current logged in user.
func (s *UserSession) SetKey(key *vsafe.Key) {
  if key == nil {
    delete(s.Values, kKeyKey)
  } else {
    s.Values[kKeyKey] = key
  }
}

// NewTemplate returns a new template instance. name is the name
// of the template; templateStr is the template string.
func NewTemplate(name, templateStr string) *template.Template {
  return template.Must(template.New(name).Parse(templateStr))
}

type userGetter struct {
  vsafedb.UserByIdRunner
}

func (g userGetter) GetUser(id int64) (interface{}, error) {
  var user vsafe.User
  if err := g.UserById(nil, id, &user); err != nil {
    return nil, err
  }
  return &user, nil
}

type sessionKeyType int

const (
  kKeyKey sessionKeyType = iota
)

<|endoftext|>


<commit_before>// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package server

import (
	"context"
	"errors"
	"testing"

	"github.com/golang/mock/gomock"
	"github.com/golang/protobuf/proto"
	"github.com/google/trillian"
	"github.com/google/trillian/extension"
	"github.com/google/trillian/storage"
	stestonly "github.com/google/trillian/storage/testonly"
	"github.com/kylelemons/godebug/pretty"
)

const (
	mapID1 = int64(1)
)

func TestIsHealthy(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	tests := []struct {
		desc string
		accessibleErr error
		wantErr bool
	}{
		{"healthy", nil, false},
		{"unhealthy", errors.New("DB not happy"), true},
	}

	for _, test := range tests {
		mockStorage := storage.NewMockMapStorage(ctrl)
		mockStorage.EXPECT().CheckDatabaseAccessible(gomock.Any()).Return(test.accessibleErr)

		server := NewTrillianMapServer(extension.Registry{
			AdminStorage: mockAdminStorageForMap(ctrl, mapID1),
			MapStorage:   mockStorage,
		})

		err := server.IsHealthy()
		if gotErr := err != nil; gotErr != test.wantErr {
			t.Errorf("%s: IsHealthy() err? %t want? %t (err=%v)", test.desc, gotErr, test.wantErr, err)
		}
	}
}

func TestGetSignedMapRoot(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	ctx := context.Background()

	tests := []struct {
		desc string
		req *trillian.GetSignedMapRootRequest
		mapRoot trillian.SignedMapRoot
		snapShErr, lsmrErr error
		wantErr bool
	}{
		{
			desc: "Unknown map",
			req: &trillian.GetSignedMapRootRequest{},
			snapShErr: errors.New("unknown map"),
			wantErr: true,
		},
		{
			desc: "Map is empty, head at revision 0",
			req: &trillian.GetSignedMapRootRequest{MapId: mapID1},
			lsmrErr: errors.New("sql: no rows in result set"),
			wantErr: true,
		},
		{
			desc: "Map has leaves, head > revision 0",
			req: &trillian.GetSignedMapRootRequest{MapId: mapID1},
			mapRoot: trillian.SignedMapRoot{
			},
		},
	}

	for _, test := range tests {
		mockStorage := storage.NewMockMapStorage(ctrl)
		mockTx := storage.NewMockMapTreeTX(ctrl)

		mockStorage.EXPECT().SnapshotForTree(gomock.Any(), test.req.MapId).Return(mockTx, test.snapShErr)
		if test.snapShErr == nil {
			mockTx.EXPECT().LatestSignedMapRoot(gomock.Any()).Return(test.mapRoot, test.lsmrErr)
			if test.lsmrErr == nil {
				mockTx.EXPECT().Commit().Return(nil)
			}
			mockTx.EXPECT().Close().Return(nil)
			mockTx.EXPECT().IsOpen().AnyTimes().Return(false)
		}

		server := NewTrillianMapServer(extension.Registry{
			AdminStorage: mockAdminStorageForMap(ctrl, mapID1),
			MapStorage:   mockStorage,
		})

		smrResp, err := server.GetSignedMapRoot(ctx, test.req)

		if gotErr := err != nil; gotErr != test.wantErr {
			t.Errorf("%s: GetSignedMapRoot()=_, err? %t want? %t (err=%v)", test.desc, gotErr, test.wantErr, err)
		}
		if err != nil {
			continue
		}
		want := &trillian.GetSignedMapRootResponse{MapRoot: &test.mapRoot}
		if got := smrResp; !proto.Equal(got, want) {
			diff := pretty.Compare(got, want)
			t.Errorf("%s: GetSignedMapRoot() got != want, diff:\n%v", test.desc, diff)
		}
	}
}

func mockAdminStorageForMap(ctrl *gomock.Controller, treeID int64) storage.AdminStorage {
	tree := *stestonly.MapTree
	tree.TreeId = treeID

	adminStorage := storage.NewMockAdminStorage(ctrl)
	adminTX := storage.NewMockReadOnlyAdminTX(ctrl)

	adminStorage.EXPECT().Snapshot(gomock.Any()).MaxTimes(1).Return(adminTX, nil)
	adminTX.EXPECT().GetTree(gomock.Any(), treeID).MaxTimes(1).Return(&tree, nil)
	adminTX.EXPECT().Close().MaxTimes(1).Return(nil)
	adminTX.EXPECT().Commit().MaxTimes(1).Return(nil)

	return adminStorage
}
<commit_msg>Add tests for GetSignedMapRootByRevision. (#871)<commit_after>// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package server

import (
	"context"
	"errors"
	"testing"

	"github.com/golang/mock/gomock"
	"github.com/golang/protobuf/proto"
	sigpb "github.com/google/trillian/crypto/sigpb"
	"github.com/google/trillian"
	"github.com/google/trillian/extension"
	"github.com/google/trillian/storage"
	stestonly "github.com/google/trillian/storage/testonly"
	"github.com/kylelemons/godebug/pretty"
)

const (
	mapID1 = int64(1)
)

var (
	signedMapRootID1Rev1 = trillian.SignedMapRoot{
		TimestampNanos: 1508235889834964600,
		RootHash: []byte("\306h\237\020\201*\t\200\227m\2253\3308u(!f\025\225g\3545\025W\026\301A:\365=j"),
		Signature: &sigpb.DigitallySigned{
			HashAlgorithm: sigpb.DigitallySigned_SHA256,
			SignatureAlgorithm: sigpb.DigitallySigned_ECDSA,
			Signature: []byte("0F\002!\000\307b\255\223\353\23615&\022\263\323\341\342+\276\274$\rX?\366\014U\362\006\376\0269rcm\002!\000\241*\255\220\301\263D\033\275\374\340A\377\337\354\202\331%au\3179\000O\r9\237\302\021\r\363\263"),
		},
		MapId: mapID1,
		MapRevision: 1,
	}
)

func TestIsHealthy(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	tests := []struct {
		desc string
		accessibleErr error
	}{
		{"healthy", nil},
		{"unhealthy", errors.New("DB not happy")},
	}

	for _, test := range tests {
		mockStorage := storage.NewMockMapStorage(ctrl)
		mockStorage.EXPECT().CheckDatabaseAccessible(gomock.Any()).Return(test.accessibleErr)

		server := NewTrillianMapServer(extension.Registry{
			AdminStorage: mockAdminStorageForMap(ctrl, mapID1),
			MapStorage:   mockStorage,
		})

		wantErr := test.accessibleErr != nil
		err := server.IsHealthy()
		if gotErr := err != nil; gotErr != wantErr {
			t.Errorf("%s: IsHealthy() err? %t want? %t (err=%v)", test.desc, gotErr, wantErr, err)
		}
	}
}

func TestGetSignedMapRoot(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	ctx := context.Background()

	tests := []struct {
		desc string
		req *trillian.GetSignedMapRootRequest
		mapRoot trillian.SignedMapRoot
		snapShErr, lsmrErr error
	}{
		{
			desc: "Unknown map",
			req: &trillian.GetSignedMapRootRequest{},
			snapShErr: errors.New("unknown map"),
		},
		{
			desc: "Map is empty, head at revision 0",
			req: &trillian.GetSignedMapRootRequest{MapId: mapID1},
			lsmrErr: errors.New("sql: no rows in result set"),
		},
		{
			desc: "Map has leaves, head > revision 0",
			req: &trillian.GetSignedMapRootRequest{MapId: mapID1},
			mapRoot: signedMapRootID1Rev1,
		},
	}

	for _, test := range tests {
		mockStorage := storage.NewMockMapStorage(ctrl)
		mockTx := storage.NewMockMapTreeTX(ctrl)

		mockStorage.EXPECT().SnapshotForTree(gomock.Any(), test.req.MapId).Return(mockTx, test.snapShErr)
		if test.snapShErr == nil {
			mockTx.EXPECT().LatestSignedMapRoot(gomock.Any()).Return(test.mapRoot, test.lsmrErr)
			if test.lsmrErr == nil {
				mockTx.EXPECT().Commit().Return(nil)
			}
			mockTx.EXPECT().Close().Return(nil)
			mockTx.EXPECT().IsOpen().AnyTimes().Return(false)
		}

		server := NewTrillianMapServer(extension.Registry{
			AdminStorage: mockAdminStorageForMap(ctrl, mapID1),
			MapStorage:   mockStorage,
		})

		smrResp, err := server.GetSignedMapRoot(ctx, test.req)

		wantErr := test.snapShErr != nil || test.lsmrErr != nil
		if gotErr := err != nil; gotErr != wantErr {
			t.Errorf("%s: GetSignedMapRoot()=_, err? %t want? %t (err=%v)", test.desc, gotErr, wantErr, err)
		}
		if err != nil {
			continue
		}
		want := &trillian.GetSignedMapRootResponse{MapRoot: &test.mapRoot}
		if got := smrResp; !proto.Equal(got, want) {
			diff := pretty.Compare(got, want)
			t.Errorf("%s: GetSignedMapRoot() got != want, diff:\n%v", test.desc, diff)
		}
	}
}

func TestGetSignedMapRootByRevision(t *testing.T) {
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	ctx := context.Background()

	tests := []struct {
		desc string
		req *trillian.GetSignedMapRootByRevisionRequest
		mapRoot trillian.SignedMapRoot
		snapShErr, lsmrErr error
	}{
		{
			desc: "Unknown map",
			req: &trillian.GetSignedMapRootByRevisionRequest{},
			snapShErr: errors.New("unknown map"),
		},
		{
			desc: "Request revision 0 for empty map",
			req: &trillian.GetSignedMapRootByRevisionRequest{MapId: mapID1},
			lsmrErr: errors.New("sql: no rows in result set"),
		},
		{
			desc: "Request latest revision (-1) for empty map",
			req: &trillian.GetSignedMapRootByRevisionRequest{MapId: mapID1, Revision: -1},
			lsmrErr: errors.New("sql: no rows in result set"),
		},
		{
			desc: "Request future revision (-1) for empty map",
			req: &trillian.GetSignedMapRootByRevisionRequest{MapId: mapID1, Revision: 123},
			lsmrErr: errors.New("sql: no rows in result set"),
		},
		{
			desc: "Request revision >0 for non-empty map",
			req: &trillian.GetSignedMapRootByRevisionRequest{MapId: mapID1, Revision: 1},
			mapRoot: signedMapRootID1Rev1,
		},
	}

	for _, test := range tests {
		mockStorage := storage.NewMockMapStorage(ctrl)
		mockTx := storage.NewMockMapTreeTX(ctrl)

		mockStorage.EXPECT().SnapshotForTree(gomock.Any(), test.req.MapId).Return(mockTx, test.snapShErr)
		if test.snapShErr == nil {
			mockTx.EXPECT().GetSignedMapRoot(gomock.Any(), test.req.Revision).Return(test.mapRoot, test.lsmrErr)
			if test.lsmrErr == nil {
				mockTx.EXPECT().Commit().Return(nil)
			}
			mockTx.EXPECT().Close().Return(nil)
			mockTx.EXPECT().IsOpen().AnyTimes().Return(false)
		}

		server := NewTrillianMapServer(extension.Registry{
			AdminStorage: mockAdminStorageForMap(ctrl, mapID1),
			MapStorage:   mockStorage,
		})

		smrResp, err := server.GetSignedMapRootByRevision(ctx, test.req)

		wantErr := test.snapShErr != nil || test.lsmrErr != nil
		if gotErr := err != nil; gotErr != wantErr {
			t.Errorf("%s: GetSignedMapRootByRevision()=_, err? %t want? %t (err=%v)", test.desc, gotErr, wantErr, err)
		}
		if err != nil {
			continue
		}
		want := &trillian.GetSignedMapRootResponse{MapRoot: &test.mapRoot}
		if got := smrResp; !proto.Equal(got, want) {
			diff := pretty.Compare(got, want)
			t.Errorf("%s: GetSignedMapRootByRevision() got != want, diff:\n%v", test.desc, diff)
		}
	}
}

func mockAdminStorageForMap(ctrl *gomock.Controller, treeID int64) storage.AdminStorage {
	tree := *stestonly.MapTree
	tree.TreeId = treeID

	adminStorage := storage.NewMockAdminStorage(ctrl)
	adminTX := storage.NewMockReadOnlyAdminTX(ctrl)

	adminStorage.EXPECT().Snapshot(gomock.Any()).MaxTimes(1).Return(adminTX, nil)
	adminTX.EXPECT().GetTree(gomock.Any(), treeID).MaxTimes(1).Return(&tree, nil)
	adminTX.EXPECT().Close().MaxTimes(1).Return(nil)
	adminTX.EXPECT().Commit().MaxTimes(1).Return(nil)

	return adminStorage
}
<|endoftext|>