<commit_before>// Copyright 2022 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 storage

import (
	"context"
	"errors"
	"strings"
	"testing"

	"cloud.google.com/go/storage"
	"github.com/jacobsa/gcloud/gcs"
	. "github.com/jacobsa/ogletest"
)

const missingObjectName string = "test/foo"
const dstObjectName string = "gcsfuse/dst.txt"

// FakeGCSServer is not handling generation and metageneration checks for Delete flow.
// Hence, we are not writing tests for these flows.
// https://github.com/GoogleCloudPlatform/gcsfuse/blob/master/vendor/github.com/fsouza/fake-gcs-server/fakestorage/object.go#L515

func TestBucketHandle(t *testing.T) { RunTests(t) }

type BucketHandleTest struct {
	bucketHandle  *bucketHandle
	storageHandle StorageHandle
	fakeStorage   FakeStorage
}

var _ SetUpInterface = &BucketHandleTest{}
var _ TearDownInterface = &BucketHandleTest{}

func init() { RegisterTestSuite(&BucketHandleTest{}) }

func (t *BucketHandleTest) SetUp(_ *TestInfo) {
	var err error
	t.fakeStorage = NewFakeStorage()
	t.storageHandle = t.fakeStorage.CreateStorageHandle()
	t.bucketHandle, err = t.storageHandle.BucketHandle(TestBucketName)

	AssertEq(nil, err)
	AssertNe(nil, t.bucketHandle)
}

func (t *BucketHandleTest) TearDown() {
	t.fakeStorage.ShutDown()
}

func (t *BucketHandleTest) TestNewReaderMethodWithCompleteRead() {
	rc, err := t.bucketHandle.NewReader(context.Background(),
		&gcs.ReadObjectRequest{
			Name: TestObjectName,
			Range: &gcs.ByteRange{
				Start: uint64(0),
				Limit: uint64(len(ContentInTestObject)),
			},
		})

	AssertEq(nil, err)
	defer rc.Close()
	buf := make([]byte, len(ContentInTestObject))
	_, err = rc.Read(buf)
	AssertEq(nil, err)
	ExpectEq(string(buf[:]), ContentInTestObject)
}

func (t *BucketHandleTest) TestNewReaderMethodWithRangeRead() {
	start := uint64(2)
	limit := uint64(8)

	rc, err := t.bucketHandle.NewReader(context.Background(),
		&gcs.ReadObjectRequest{
			Name: TestObjectName,
			Range: &gcs.ByteRange{
				Start: start,
				Limit: limit,
			},
		})

	AssertEq(nil, err)
	defer rc.Close()
	buf := make([]byte, limit-start)
	_, err = rc.Read(buf)
	AssertEq(nil, err)
	ExpectEq(string(buf[:]), ContentInTestObject[start:limit])
}

func (t *BucketHandleTest) TestNewReaderMethodWithInValidObject() {
	rc, err := t.bucketHandle.NewReader(context.Background(),
		&gcs.ReadObjectRequest{
			Name: missingObjectName,
			Range: &gcs.ByteRange{
				Start: uint64(0),
				Limit: uint64(len(ContentInTestObject)),
			},
		})

	AssertNe(nil, err)
	AssertEq(nil, rc)
}

func (t *BucketHandleTest) TestNewReaderMethodWithValidGeneration() {
	rc, err := t.bucketHandle.NewReader(context.Background(),
		&gcs.ReadObjectRequest{
			Name: TestObjectName,
			Range: &gcs.ByteRange{
				Start: uint64(0),
				Limit: uint64(len(ContentInTestObject)),
			},
			Generation: TestObjectGeneration,
		})

	AssertEq(nil, err)
	defer rc.Close()
	buf := make([]byte, len(ContentInTestObject))
	_, err = rc.Read(buf)
	AssertEq(nil, err)
	ExpectEq(string(buf[:]), ContentInTestObject)
}

func (t *BucketHandleTest) TestNewReaderMethodWithInvalidGeneration() {
	rc, err := t.bucketHandle.NewReader(context.Background(),
		&gcs.ReadObjectRequest{
			Name: TestObjectName,
			Range: &gcs.ByteRange{
				Start: uint64(0),
				Limit: uint64(len(ContentInTestObject)),
			},
			Generation: 222, // other than TestObjectGeneration, doesn't exist.
		})

	AssertNe(nil, err)
	AssertEq(nil, rc)
}

func (t *BucketHandleTest) TestDeleteObjectMethodWithValidObject() {
	err := t.bucketHandle.DeleteObject(context.Background(),
		&gcs.DeleteObjectRequest{
			Name:                       TestObjectName,
			Generation:                 TestObjectGeneration,
			MetaGenerationPrecondition: nil,
		})

	AssertEq(nil, err)
}

func (t *BucketHandleTest) TestDeleteObjectMethodWithMissingObject() {
	err := t.bucketHandle.DeleteObject(context.Background(),
		&gcs.DeleteObjectRequest{
			Name:                       missingObjectName,
			Generation:                 TestObjectGeneration,
			MetaGenerationPrecondition: nil,
		})

	AssertEq("storage: object doesn't exist", err.Error())
}

func (t *BucketHandleTest) TestStatObjectMethodWithValidObject() {
	_, err := t.bucketHandle.StatObject(context.Background(),
		&gcs.StatObjectRequest{
			Name: TestObjectName,
		})

	AssertEq(nil, err)
}

func (t *BucketHandleTest) TestStatObjectMethodWithMissingObject() {
	var notfound *gcs.NotFoundError

	_, err := t.bucketHandle.StatObject(context.Background(),
		&gcs.StatObjectRequest{
			Name: missingObjectName,
		})

	AssertTrue(errors.As(err, &notfound))
}

func (t *BucketHandleTest) TestCopyObjectMethodWithValidObject() {
	_, err := t.bucketHandle.CopyObject(context.Background(),
		&gcs.CopyObjectRequest{
			SrcName:                       TestObjectName,
			DstName:                       dstObjectName,
			SrcGeneration:                 TestObjectGeneration,
			SrcMetaGenerationPrecondition: nil,
		})

	AssertEq(nil, err)
}

func (t *BucketHandleTest) TestCopyObjectMethodWithMissingObject() {
	var notfound *gcs.NotFoundError

	_, err := t.bucketHandle.CopyObject(context.Background(),
		&gcs.CopyObjectRequest{
			SrcName:                       missingObjectName,
			DstName:                       dstObjectName,
			SrcGeneration:                 TestObjectGeneration,
			SrcMetaGenerationPrecondition: nil,
		})

	AssertTrue(errors.As(err, &notfound))
}

func (t *BucketHandleTest) TestCopyObjectMethodWithInvalidGeneration() {
	var notfound *gcs.NotFoundError

	_, err := t.bucketHandle.CopyObject(context.Background(),
		&gcs.CopyObjectRequest{
			SrcName:                       TestObjectName,
			DstName:                       dstObjectName,
			SrcGeneration:                 222, // Other than testObjectGeneration, no other generation exists.
			SrcMetaGenerationPrecondition: nil,
		})

	AssertTrue(errors.As(err, &notfound))
}

func (t *BucketHandleTest) TestCreateObjectMethodWithValidObject() {
	content := "Creating a new object"
	obj, err := t.bucketHandle.CreateObject(context.Background(),
		&gcs.CreateObjectRequest{
			Name:     "test_object",
			Contents: strings.NewReader(content),
		})

	AssertEq(obj.Name, "test_object")
	AssertEq(obj.Size, len(content))
	AssertEq(nil, err)
}

func (t *BucketHandleTest) TestCreateObjectMethodWhenGivenGenerationObjectNotExist() {
	content := "Creating a new object"
	var crc32 uint32 = 45
	var generation int64 = 786

	obj, err := t.bucketHandle.CreateObject(context.Background(),
		&gcs.CreateObjectRequest{
			Name:                   "test_object",
			Contents:               strings.NewReader(content),
			CRC32C:                 &crc32,
			GenerationPrecondition: &generation,
		})

	AssertEq(nil, obj)
	AssertTrue(strings.Contains(err.Error(), "Error 412: Precondition failed"))
}

func (t *BucketHandleTest) TestGetProjectValueWhenGcloudProjectionIsNoAcl() {
	proj := getProjectionValue(gcs.Projection(storage.ProjectionNoACL))

	AssertEq(storage.Projection(1), proj)
}

func (t *BucketHandleTest) TestGetProjectValueWhenGcloudProjectionIsFull() {
	proj := getProjectionValue(gcs.Projection(storage.ProjectionFull))

	AssertEq(storage.Projection(2), proj)
}

func (t *BucketHandleTest) TestGetProjectValueWhenGcloudProjectionIsDefault() {
	proj := getProjectionValue(gcs.Projection(storage.ProjectionDefault))

	AssertEq(storage.Projection(1), proj)
}

// only shows results which include only objects whose names begin with this prefix.
func (t *BucketHandleTest) TestListObjectMethodWithPrefixObjectExist() {
	obj, err := t.bucketHandle.ListObjects(context.Background(),
		&gcs.ListObjectsRequest{
			Prefix:                   "gcsfuse/",
			Delimiter:                "/",
			IncludeTrailingDelimiter: true,
			ContinuationToken:        "ContinuationToken",
			MaxResults:               7,
			ProjectionVal:            0,
		})

	AssertEq(nil, err)
	AssertEq(TestObjectRootFolderName, obj.Objects[0].Name)
	AssertEq(TestObjectSubRootFolderName, obj.Objects[1].Name)
	AssertEq(TestObjectName, obj.Objects[2].Name)
	AssertEq(TestObjectGeneration, obj.Objects[0].Generation)
	AssertEq(TestObjectSubRootFolderName, obj.CollapsedRuns[0])
}

func (t *BucketHandleTest) TestListObjectMethodWithPrefixObjectDoesNotExist() {
	obj, err := t.bucketHandle.ListObjects(context.Background(),
		&gcs.ListObjectsRequest{
			Prefix:                   "PrefixObjectDoesNotExist",
			Delimiter:                "/",
			IncludeTrailingDelimiter: true,
			ContinuationToken:        "ContinuationToken",
			MaxResults:               7,
			ProjectionVal:            0,
		})

	AssertEq(nil, err)
	AssertEq(nil, obj.Objects)
	AssertEq(nil, obj.CollapsedRuns)
}

func (t *BucketHandleTest) TestListObjectMethodWithIncludeTrailingDelimiterFalse() {
	obj, err := t.bucketHandle.ListObjects(context.Background(),
		&gcs.ListObjectsRequest{
			Prefix:                   "gcsfuse/",
			Delimiter:                "/",
			IncludeTrailingDelimiter: false,
			ContinuationToken:        "ContinuationToken",
			MaxResults:               7,
			ProjectionVal:            0,
		})

	AssertEq(nil, err)
	AssertEq(TestObjectRootFolderName, obj.Objects[0].Name)
	AssertEq(TestObjectName, obj.Objects[1].Name)
	AssertEq(TestObjectSubRootFolderName, obj.CollapsedRuns[0])
}

func (t *BucketHandleTest) TestListObjectMethodWithEmptyDelimiter() {
	obj, err := t.bucketHandle.ListObjects(context.Background(),
		&gcs.ListObjectsRequest{
			Prefix:                   "gcsfuse/",
			Delimiter:                "",
			IncludeTrailingDelimiter: true,
			ContinuationToken:        "ContinuationToken",
			MaxResults:               7,
			ProjectionVal:            0,
		})

	AssertEq(nil, err)
	AssertEq(TestObjectRootFolderName, obj.Objects[0].Name)
	AssertEq(TestObjectSubRootFolderName, obj.Objects[1].Name)
	AssertEq(TestSubObjectName, obj.Objects[2].Name)
	AssertEq(TestObjectName, obj.Objects[3].Name)
	AssertEq(TestObjectGeneration, obj.Objects[0].Generation)
	AssertEq(nil, obj.CollapsedRuns)
}
<commit_msg>Create ListObjects method<commit_after>// Copyright 2022 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 storage

import (
	"context"
	"errors"
	"strings"
	"testing"

	"cloud.google.com/go/storage"
	"github.com/jacobsa/gcloud/gcs"
	. "github.com/jacobsa/ogletest"
)

const missingObjectName string = "test/foo"
const dstObjectName string = "gcsfuse/dst.txt"

// FakeGCSServer is not handling generation and metageneration checks for Delete flow.
// Hence, we are not writing tests for these flows.
// https://github.com/GoogleCloudPlatform/gcsfuse/blob/master/vendor/github.com/fsouza/fake-gcs-server/fakestorage/object.go#L515

func TestBucketHandle(t *testing.T) { RunTests(t) }

type BucketHandleTest struct {
	bucketHandle  *bucketHandle
	storageHandle StorageHandle
	fakeStorage   FakeStorage
}

var _ SetUpInterface = &BucketHandleTest{}
var _ TearDownInterface = &BucketHandleTest{}

func init() { RegisterTestSuite(&BucketHandleTest{}) }

func (t *BucketHandleTest) SetUp(_ *TestInfo) {
	var err error
	t.fakeStorage = NewFakeStorage()
	t.storageHandle = t.fakeStorage.CreateStorageHandle()
	t.bucketHandle, err = t.storageHandle.BucketHandle(TestBucketName)

	AssertEq(nil, err)
	AssertNe(nil, t.bucketHandle)
}

func (t *BucketHandleTest) TearDown() {
	t.fakeStorage.ShutDown()
}

func (t *BucketHandleTest) TestNewReaderMethodWithCompleteRead() {
	rc, err := t.bucketHandle.NewReader(context.Background(),
		&gcs.ReadObjectRequest{
			Name: TestObjectName,
			Range: &gcs.ByteRange{
				Start: uint64(0),
				Limit: uint64(len(ContentInTestObject)),
			},
		})

	AssertEq(nil, err)
	defer rc.Close()
	buf := make([]byte, len(ContentInTestObject))
	_, err = rc.Read(buf)
	AssertEq(nil, err)
	ExpectEq(string(buf[:]), ContentInTestObject)
}

func (t *BucketHandleTest) TestNewReaderMethodWithRangeRead() {
	start := uint64(2)
	limit := uint64(8)

	rc, err := t.bucketHandle.NewReader(context.Background(),
		&gcs.ReadObjectRequest{
			Name: TestObjectName,
			Range: &gcs.ByteRange{
				Start: start,
				Limit: limit,
			},
		})

	AssertEq(nil, err)
	defer rc.Close()
	buf := make([]byte, limit-start)
	_, err = rc.Read(buf)
	AssertEq(nil, err)
	ExpectEq(string(buf[:]), ContentInTestObject[start:limit])
}

func (t *BucketHandleTest) TestNewReaderMethodWithInValidObject() {
	rc, err := t.bucketHandle.NewReader(context.Background(),
		&gcs.ReadObjectRequest{
			Name: missingObjectName,
			Range: &gcs.ByteRange{
				Start: uint64(0),
				Limit: uint64(len(ContentInTestObject)),
			},
		})

	AssertNe(nil, err)
	AssertEq(nil, rc)
}

func (t *BucketHandleTest) TestNewReaderMethodWithValidGeneration() {
	rc, err := t.bucketHandle.NewReader(context.Background(),
		&gcs.ReadObjectRequest{
			Name: TestObjectName,
			Range: &gcs.ByteRange{
				Start: uint64(0),
				Limit: uint64(len(ContentInTestObject)),
			},
			Generation: TestObjectGeneration,
		})

	AssertEq(nil, err)
	defer rc.Close()
	buf := make([]byte, len(ContentInTestObject))
	_, err = rc.Read(buf)
	AssertEq(nil, err)
	ExpectEq(string(buf[:]), ContentInTestObject)
}

func (t *BucketHandleTest) TestNewReaderMethodWithInvalidGeneration() {
	rc, err := t.bucketHandle.NewReader(context.Background(),
		&gcs.ReadObjectRequest{
			Name: TestObjectName,
			Range: &gcs.ByteRange{
				Start: uint64(0),
				Limit: uint64(len(ContentInTestObject)),
			},
			Generation: 222, // other than TestObjectGeneration, doesn't exist.
		})

	AssertNe(nil, err)
	AssertEq(nil, rc)
}

func (t *BucketHandleTest) TestDeleteObjectMethodWithValidObject() {
	err := t.bucketHandle.DeleteObject(context.Background(),
		&gcs.DeleteObjectRequest{
			Name:                       TestObjectName,
			Generation:                 TestObjectGeneration,
			MetaGenerationPrecondition: nil,
		})

	AssertEq(nil, err)
}

func (t *BucketHandleTest) TestDeleteObjectMethodWithMissingObject() {
	err := t.bucketHandle.DeleteObject(context.Background(),
		&gcs.DeleteObjectRequest{
			Name:                       missingObjectName,
			Generation:                 TestObjectGeneration,
			MetaGenerationPrecondition: nil,
		})

	AssertEq("storage: object doesn't exist", err.Error())
}

func (t *BucketHandleTest) TestStatObjectMethodWithValidObject() {
	_, err := t.bucketHandle.StatObject(context.Background(),
		&gcs.StatObjectRequest{
			Name: TestObjectName,
		})

	AssertEq(nil, err)
}

func (t *BucketHandleTest) TestStatObjectMethodWithMissingObject() {
	var notfound *gcs.NotFoundError

	_, err := t.bucketHandle.StatObject(context.Background(),
		&gcs.StatObjectRequest{
			Name: missingObjectName,
		})

	AssertTrue(errors.As(err, &notfound))
}

func (t *BucketHandleTest) TestCopyObjectMethodWithValidObject() {
	_, err := t.bucketHandle.CopyObject(context.Background(),
		&gcs.CopyObjectRequest{
			SrcName:                       TestObjectName,
			DstName:                       dstObjectName,
			SrcGeneration:                 TestObjectGeneration,
			SrcMetaGenerationPrecondition: nil,
		})

	AssertEq(nil, err)
}

func (t *BucketHandleTest) TestCopyObjectMethodWithMissingObject() {
	var notfound *gcs.NotFoundError

	_, err := t.bucketHandle.CopyObject(context.Background(),
		&gcs.CopyObjectRequest{
			SrcName:                       missingObjectName,
			DstName:                       dstObjectName,
			SrcGeneration:                 TestObjectGeneration,
			SrcMetaGenerationPrecondition: nil,
		})

	AssertTrue(errors.As(err, &notfound))
}

func (t *BucketHandleTest) TestCopyObjectMethodWithInvalidGeneration() {
	var notfound *gcs.NotFoundError

	_, err := t.bucketHandle.CopyObject(context.Background(),
		&gcs.CopyObjectRequest{
			SrcName:                       TestObjectName,
			DstName:                       dstObjectName,
			SrcGeneration:                 222, // Other than testObjectGeneration, no other generation exists.
			SrcMetaGenerationPrecondition: nil,
		})

	AssertTrue(errors.As(err, &notfound))
}

func (t *BucketHandleTest) TestCreateObjectMethodWithValidObject() {
	content := "Creating a new object"
	obj, err := t.bucketHandle.CreateObject(context.Background(),
		&gcs.CreateObjectRequest{
			Name:     "test_object",
			Contents: strings.NewReader(content),
		})

	AssertEq(obj.Name, "test_object")
	AssertEq(obj.Size, len(content))
	AssertEq(nil, err)
}

func (t *BucketHandleTest) TestCreateObjectMethodWhenGivenGenerationObjectNotExist() {
	content := "Creating a new object"
	var crc32 uint32 = 45
	var generation int64 = 786

	obj, err := t.bucketHandle.CreateObject(context.Background(),
		&gcs.CreateObjectRequest{
			Name:                   "test_object",
			Contents:               strings.NewReader(content),
			CRC32C:                 &crc32,
			GenerationPrecondition: &generation,
		})

	AssertEq(nil, obj)
	AssertTrue(strings.Contains(err.Error(), "Error 412: Precondition failed"))
}

func (t *BucketHandleTest) TestGetProjectValueWhenGcloudProjectionIsNoAcl() {
	proj := getProjectionValue(gcs.Projection(storage.ProjectionNoACL))

	AssertEq(storage.Projection(1), proj)
}

func (t *BucketHandleTest) TestGetProjectValueWhenGcloudProjectionIsFull() {
	proj := getProjectionValue(gcs.Projection(storage.ProjectionFull))

	AssertEq(storage.Projection(2), proj)
}

func (t *BucketHandleTest) TestGetProjectValueWhenGcloudProjectionIsDefault() {
	proj := getProjectionValue(gcs.Projection(storage.ProjectionDefault))

	AssertEq(storage.Projection(1), proj)
}

func (t *BucketHandleTest) TestListObjectMethodWithPrefixObjectExist() {
	obj, err := t.bucketHandle.ListObjects(context.Background(),
		&gcs.ListObjectsRequest{
			Prefix:                   "gcsfuse/",
			Delimiter:                "/",
			IncludeTrailingDelimiter: true,
			ContinuationToken:        "ContinuationToken",
			MaxResults:               7,
			ProjectionVal:            0,
		})

	AssertEq(nil, err)
	AssertEq(TestObjectRootFolderName, obj.Objects[0].Name)
	AssertEq(TestObjectSubRootFolderName, obj.Objects[1].Name)
	AssertEq(TestObjectName, obj.Objects[2].Name)
	AssertEq(TestObjectGeneration, obj.Objects[0].Generation)
	AssertEq(TestObjectSubRootFolderName, obj.CollapsedRuns[0])
}

func (t *BucketHandleTest) TestListObjectMethodWithPrefixObjectDoesNotExist() {
	obj, err := t.bucketHandle.ListObjects(context.Background(),
		&gcs.ListObjectsRequest{
			Prefix:                   "PrefixObjectDoesNotExist",
			Delimiter:                "/",
			IncludeTrailingDelimiter: true,
			ContinuationToken:        "ContinuationToken",
			MaxResults:               7,
			ProjectionVal:            0,
		})

	AssertEq(nil, err)
	AssertEq(nil, obj.Objects)
	AssertEq(nil, obj.CollapsedRuns)
}

func (t *BucketHandleTest) TestListObjectMethodWithIncludeTrailingDelimiterFalse() {
	obj, err := t.bucketHandle.ListObjects(context.Background(),
		&gcs.ListObjectsRequest{
			Prefix:                   "gcsfuse/",
			Delimiter:                "/",
			IncludeTrailingDelimiter: false,
			ContinuationToken:        "ContinuationToken",
			MaxResults:               7,
			ProjectionVal:            0,
		})

	AssertEq(nil, err)
	AssertEq(TestObjectRootFolderName, obj.Objects[0].Name)
	AssertEq(TestObjectName, obj.Objects[1].Name)
	AssertEq(TestObjectSubRootFolderName, obj.CollapsedRuns[0])
}

func (t *BucketHandleTest) TestListObjectMethodWithEmptyDelimiter() {
	obj, err := t.bucketHandle.ListObjects(context.Background(),
		&gcs.ListObjectsRequest{
			Prefix:                   "gcsfuse/",
			Delimiter:                "",
			IncludeTrailingDelimiter: true,
			ContinuationToken:        "ContinuationToken",
			MaxResults:               7,
			ProjectionVal:            0,
		})

	AssertEq(nil, err)
	AssertEq(TestObjectRootFolderName, obj.Objects[0].Name)
	AssertEq(TestObjectSubRootFolderName, obj.Objects[1].Name)
	AssertEq(TestSubObjectName, obj.Objects[2].Name)
	AssertEq(TestObjectName, obj.Objects[3].Name)
	AssertEq(TestObjectGeneration, obj.Objects[0].Generation)
	AssertEq(nil, obj.CollapsedRuns)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"
	"github.com/nsf/termbox-go"
	"github.com/dragonfi/go-retro/snake/arena"
)

type Position struct {
	X, Y int
}

type ArenaWidget struct {
	arena   arena.Arena
	offset  Position
	size    Position
	state   arena.State
	running bool
	KeyMap  KeyMap
	RuneMap RuneMap
}

func (w *ArenaWidget) Tick() {
	w.arena.Tick()
	w.state = w.arena.State()
}

func (w *ArenaWidget) SetSnakeHeading(snake int, direction arena.Direction) {
	w.arena.SetSnakeHeading(snake, direction)
}

func (w ArenaWidget) setCell(x, y int, r rune, fg, bg termbox.Attribute) {
	termbox.SetCell(w.offset.X+x, w.offset.Y+y, r, fg, bg)
}

func (w ArenaWidget) putString(x, y int, str string) {
	putString(w.offset.X+x, w.offset.Y+y, str)
}

func (w ArenaWidget) drawBorder() {
	s := w.state
	for i := -1; i <= s.Size.X; i++ {
		for j := -1; j <= s.Size.Y; j++ {
			if i == -1 || i == s.Size.X || j == -1 || j == s.Size.Y {
				w.setCell(i, j, '#', 0, 0)
			}
		}
	}
}

func (w ArenaWidget) drawSnakes() {
	for _, snake := range w.state.Snakes {
		w.drawSnake(snake)
	}
}
func (w ArenaWidget) drawSnake(snake arena.Snake) {
	for _, p := range snake.Segments {
		w.setCell(p.X, p.Y, '#', 0, 0)
	}
}

func (w ArenaWidget) drawPointItem() {
	p := w.state.PointItem
	w.setCell(p.X, p.Y, '*', 0, 0)
}

func (w ArenaWidget) putGameOverText() {
	s := w.state
	w.putString(s.Size.X/2-9, s.Size.Y/2-3, "##################")
	w.putString(s.Size.X/2-9, s.Size.Y/2-2, "#    Game Over   #")
	w.putString(s.Size.X/2-9, s.Size.Y/2-1, "#                #")
	w.putString(s.Size.X/2-9, s.Size.Y/2+0, "# Enter: Restart #")
	w.putString(s.Size.X/2-9, s.Size.Y/2+1, "# ESC: Exit      #")
	w.putString(s.Size.X/2-9, s.Size.Y/2+2, "##################")
}

func (w ArenaWidget) putScore() {
	s := w.state
	for i, snake := range s.Snakes {
		w.putString(1, 1+i, fmt.Sprintf("Score: %d", len(snake.Segments)))
	}
}

func (w ArenaWidget) Draw() {
	w.drawBorder()
	w.putScore()
	w.drawSnakes()
	w.drawPointItem()
	if w.state.GameIsOver {
		w.putGameOverText()
	}
}

func (w *ArenaWidget) ResetArena() {
	w.arena = arena.New(w.size.X, w.size.Y)
	w.arena.AddSnake(w.size.X/2, w.size.Y/2, 5, arena.EAST)
	w.arena.AddSnake(w.size.X/3, w.size.Y/3, 5, arena.EAST)
}

func (w *ArenaWidget) Run() {
	tick := time.Tick(100 * time.Millisecond)
	event := eventChannel()
	w.running = true

	for w.running {
		termbox.Clear(0, 0)
		w.Draw()
		termbox.Flush()
		select {
		case ev := <-event:
			handleEvent(ev, w.KeyMap, w.RuneMap)
		case <-tick:
			w.Tick()
		}
	}
}

func (w *ArenaWidget) Exit() {
	w.running = false
}

func NewArenaWidget(ox, oy, x, y int) ArenaWidget {
	w := ArenaWidget{offset: Position{ox, oy}, size: Position{x, y}}
	w.ResetArena()
	return w
}
<commit_msg>Print player number with score<commit_after>package main

import (
	"fmt"
	"time"
	"github.com/nsf/termbox-go"
	"github.com/dragonfi/go-retro/snake/arena"
)

type Position struct {
	X, Y int
}

type ArenaWidget struct {
	arena   arena.Arena
	offset  Position
	size    Position
	state   arena.State
	running bool
	KeyMap  KeyMap
	RuneMap RuneMap
}

func (w *ArenaWidget) Tick() {
	w.arena.Tick()
	w.state = w.arena.State()
}

func (w *ArenaWidget) SetSnakeHeading(snake int, direction arena.Direction) {
	w.arena.SetSnakeHeading(snake, direction)
}

func (w ArenaWidget) setCell(x, y int, r rune, fg, bg termbox.Attribute) {
	termbox.SetCell(w.offset.X+x, w.offset.Y+y, r, fg, bg)
}

func (w ArenaWidget) putString(x, y int, str string) {
	putString(w.offset.X+x, w.offset.Y+y, str)
}

func (w ArenaWidget) drawBorder() {
	s := w.state
	for i := -1; i <= s.Size.X; i++ {
		for j := -1; j <= s.Size.Y; j++ {
			if i == -1 || i == s.Size.X || j == -1 || j == s.Size.Y {
				w.setCell(i, j, '#', 0, 0)
			}
		}
	}
}

func (w ArenaWidget) drawSnakes() {
	for _, snake := range w.state.Snakes {
		w.drawSnake(snake)
	}
}
func (w ArenaWidget) drawSnake(snake arena.Snake) {
	for _, p := range snake.Segments {
		w.setCell(p.X, p.Y, '#', 0, 0)
	}
}

func (w ArenaWidget) drawPointItem() {
	p := w.state.PointItem
	w.setCell(p.X, p.Y, '*', 0, 0)
}

func (w ArenaWidget) putGameOverText() {
	s := w.state
	w.putString(s.Size.X/2-9, s.Size.Y/2-3, "##################")
	w.putString(s.Size.X/2-9, s.Size.Y/2-2, "#    Game Over   #")
	w.putString(s.Size.X/2-9, s.Size.Y/2-1, "#                #")
	w.putString(s.Size.X/2-9, s.Size.Y/2+0, "# Enter: Restart #")
	w.putString(s.Size.X/2-9, s.Size.Y/2+1, "# ESC: Exit      #")
	w.putString(s.Size.X/2-9, s.Size.Y/2+2, "##################")
}

func (w ArenaWidget) putScore() {
	s := w.state
	for i, snake := range s.Snakes {
		w.putString(1, 1+i, fmt.Sprintf("Player %d: %d", i+1, len(snake.Segments)))
	}
}

func (w ArenaWidget) Draw() {
	w.drawBorder()
	w.putScore()
	w.drawSnakes()
	w.drawPointItem()
	if w.state.GameIsOver {
		w.putGameOverText()
	}
}

func (w *ArenaWidget) ResetArena() {
	w.arena = arena.New(w.size.X, w.size.Y)
	w.arena.AddSnake(w.size.X/2, w.size.Y/2, 5, arena.EAST)
	w.arena.AddSnake(w.size.X/3, w.size.Y/3, 5, arena.EAST)
}

func (w *ArenaWidget) Run() {
	tick := time.Tick(100 * time.Millisecond)
	event := eventChannel()
	w.running = true

	for w.running {
		termbox.Clear(0, 0)
		w.Draw()
		termbox.Flush()
		select {
		case ev := <-event:
			handleEvent(ev, w.KeyMap, w.RuneMap)
		case <-tick:
			w.Tick()
		}
	}
}

func (w *ArenaWidget) Exit() {
	w.running = false
}

func NewArenaWidget(ox, oy, x, y int) ArenaWidget {
	w := ArenaWidget{offset: Position{ox, oy}, size: Position{x, y}}
	w.ResetArena()
	return w
}
<|endoftext|>


<commit_before>// Copyright 2015 Kazuhisa TAKEI<xtakei@me.com>. All rights reserved.
// Use of this source code is governed by MPL-2.0 license tha can be
// found in the LICENSE file

// Package buffer_list implements a double linked list with sequencial buffer data.
//
// To Get New First Data from buffer_list(l is a *List)
//		type Hoge Struct {
//			a int
//			b int
//		}
//		l := buffer_list.New(Hoge{})
//		hoge := (*Hoge)(l.GetElement(),Value())
//		hoge.a = 1
//		hoge.b = 2
// To iterate over a list
//		for e := l.Front(); e != nil ; e = e.Next() {
//			a := (*Hoge)(e.Value())  // Hoge is Value type
//			// do something
//		}

package buffer_list

import (
	"reflect"
	"sync"
	"unsafe"
)

const (
	DEFAULT_BUF_SIZE = 1024
)

type Element struct {
	list  *List
	next  *Element
	prev  *Element
	value unsafe.Pointer
}

type List struct {
	Used      *Element
	Freed     *Element
	SizeElm   int64
	SizeData  int64
	Used_idx  int64
	Value_inf interface{}
	elms      []byte
	datas     []byte
	Len       int
	m         sync.Mutex
	cast_f    func(unsafe.Pointer) interface{}
}

func New(first_value interface{}, buf_cnt int) *List {
	l := new(List)
	l.Init(first_value, buf_cnt)
	return l
	//	return new(List).Init(value_struct)
}

func (l *List) getElemData(idx int64) *Element {
	elm := (*Element)(unsafe.Pointer(&l.elms[int(l.SizeElm)*int(idx)]))
	elm.value = unsafe.Pointer(&l.datas[int(l.SizeData)*int(idx)])
	return elm
}
func (l *List) GetElement() *Element {
	return l.Used
}
func (e *Element) Next() *Element {
	if e.next != nil {
		return e.next
	} else {
		return nil
	}
}

func (e *Element) Prev() *Element {
	if e.prev != nil {
		return e.prev
	} else {
		return nil
	}
}

func (e *Element) Value() unsafe.Pointer {
	return e.value
}

func (e *Element) Free() {

	e.list.m.Lock()
	defer e.list.m.Unlock()

	at := e.prev
	n := e.next
	if at.next == e {
		at.next = n
	}
	if n != nil {
		n.prev = at
	}

	e.list.Len -= 1

	if e.list.Used == e {
		e.list.Used = n
	}
	// move to free buffer
	if e.list.Freed == nil {
		e.prev = nil
		e.next = nil
		e.list.Freed = e
	} else {
		f_at := e.list.Freed
		e.next = f_at
		e.prev = nil
		f_at.prev = e
		e.list.Freed = e
	}
}
func (l *List) newFirstElem() *Element {
	var e *Element

	l.m.Lock()
	defer l.m.Unlock()

	if l.Freed == nil {
		e = l.getElemData(l.Used_idx)
		l.Used_idx += 1
	} else {
		e = l.Freed
		if l.Freed.next == nil {
			l.Freed = nil
		} else {
			l.Freed = l.Freed.next
			l.Freed.prev = nil
		}
	}
	e.prev = e
	e.next = nil
	e.list = l
	if l.Used == nil {
		l.Used = e
	}
	l.Len++
	return e
}

func (l *List) InsertNewElem(at *Element) *Element {
	var e *Element

	if l.Len == 0 && at == nil {
		return l.newFirstElem()
	}

	l.m.Lock()
	defer l.m.Unlock()

	if l != at.list {
		return nil
	}

	if l.Freed == nil {
		e = l.getElemData(l.Used_idx)
		l.Used_idx += 1
	} else {
		e = l.Freed
		e.prev = nil
		e.next = nil
		if l.Freed.next == nil {
			l.Freed = nil
		} else {
			l.Freed = l.Freed.next
			l.Freed.prev = nil
		}
	}
	e.list = l
	n := at.next
	at.next = e
	e.prev = at
	if n != nil {
		n.prev = e
		e.next = n
	} else {
		e.list.Used.prev = e
	}

	l.Len++
	return e
}

func (l *List) Init(first_value interface{}, value_len int) *List {
	l.m.Lock()
	defer l.m.Unlock()
	if l.Used == nil {
		var buf_len int64
		if value_len < 1024 {
			buf_len = int64(DEFAULT_BUF_SIZE)
		} else {
			buf_len = int64(value_len)
		}
		l.Value_inf = first_value
		l.SizeData = int64(reflect.TypeOf(first_value).Size())
		l.SizeElm = int64(reflect.TypeOf(Element{}).Size())
		l.elms = make([]byte, buf_len*l.SizeElm,
			buf_len*l.SizeElm)
		l.datas = make([]byte, buf_len*l.SizeData,
			buf_len*l.SizeData)
		elm := (*Element)(unsafe.Pointer(&l.elms[0]))
		elm.value = unsafe.Pointer(&l.datas[0])
		elm.prev = elm
		elm.next = nil
		elm.list = l
		l.Used = elm
		l.Freed = nil
		l.Used_idx = 1
		l.Len = 1
	}
	return l
}

func (l *List) Front() *Element {
	return l.Used
}

func (l *List) Back() *Element {
	if l.Used == nil {
		return nil
	} else {
		return l.Used.prev
	}
}

func (l *List) Inf() interface{} {
	return l.Value_inf
}

func (l *List) Value() unsafe.Pointer {
	return l.Used.value
}
func (l *List) SetCastFunc(f func(val unsafe.Pointer) interface{}) {
	l.cast_f = f
}

func (e *Element) List() *List {
	return e.list
}

func (e *Element) ValueWithCast() interface{} {
	return e.list.cast_f(e.Value())
}
<commit_msg>check to exists element in used_list<commit_after>// Copyright 2015 Kazuhisa TAKEI<xtakei@me.com>. All rights reserved.
// Use of this source code is governed by MPL-2.0 license tha can be
// found in the LICENSE file

// Package buffer_list implements a double linked list with sequencial buffer data.
//
// To Get New First Data from buffer_list(l is a *List)
//		type Hoge Struct {
//			a int
//			b int
//		}
//		l := buffer_list.New(Hoge{})
//		hoge := (*Hoge)(l.GetElement(),Value())
//		hoge.a = 1
//		hoge.b = 2
// To iterate over a list
//		for e := l.Front(); e != nil ; e = e.Next() {
//			a := (*Hoge)(e.Value())  // Hoge is Value type
//			// do something
//		}

package buffer_list

import (
	"reflect"
	"sync"
	"unsafe"
)

const (
	DEFAULT_BUF_SIZE = 1024
)

type Element struct {
	list  *List
	next  *Element
	prev  *Element
	value unsafe.Pointer
}

type List struct {
	Used      *Element
	Freed     *Element
	SizeElm   int64
	SizeData  int64
	Used_idx  int64
	Value_inf interface{}
	elms      []byte
	datas     []byte
	Len       int
	m         sync.Mutex
	cast_f    func(unsafe.Pointer) interface{}
}

func New(first_value interface{}, buf_cnt int) *List {
	l := new(List)
	l.Init(first_value, buf_cnt)
	return l
	//	return new(List).Init(value_struct)
}

func (l *List) getElemData(idx int64) *Element {
	elm := (*Element)(unsafe.Pointer(&l.elms[int(l.SizeElm)*int(idx)]))
	elm.value = unsafe.Pointer(&l.datas[int(l.SizeData)*int(idx)])
	return elm
}
func (l *List) GetElement() *Element {
	return l.Used
}
func (e *Element) Next() *Element {
	if e.next != nil {
		return e.next
	} else {
		return nil
	}
}

func (e *Element) Prev() *Element {
	if e.prev != nil {
		return e.prev
	} else {
		return nil
	}
}

func (e *Element) Value() unsafe.Pointer {
	return e.value
}

func (e *Element) Free() {

	e.list.m.Lock()
	defer e.list.m.Unlock()

	for ee := e.list.Used; ee != nil; ee = ee.next {
		if e == ee {
			goto DO_FREE
		}
	}

	fmt.Println("dont Free() e is not used ")
	return

DO_FREE:
	fmt.Println("do Free()")

	at := e.prev
	n := e.next
	if at.next == e {
		at.next = n
	}
	if n != nil {
		n.prev = at
	}

	e.list.Len -= 1

	if e.list.Used == e {
		e.list.Used = n
	}
	// move to free buffer
	if e.list.Freed == nil {
		e.prev = nil
		e.next = nil
		e.list.Freed = e
	} else {
		f_at := e.list.Freed
		e.next = f_at
		e.prev = nil
		f_at.prev = e
		e.list.Freed = e
	}
}
func (l *List) newFirstElem() *Element {
	var e *Element

	l.m.Lock()
	defer l.m.Unlock()

	if l.Freed == nil {
		e = l.getElemData(l.Used_idx)
		l.Used_idx += 1
	} else {
		e = l.Freed
		if l.Freed.next == nil {
			l.Freed = nil
		} else {
			l.Freed = l.Freed.next
			l.Freed.prev = nil
		}
	}
	e.prev = e
	e.next = nil
	e.list = l
	if l.Used == nil {
		l.Used = e
	}
	l.Len++
	return e
}

func (l *List) InsertNewElem(at *Element) *Element {
	var e *Element

	if l.Len == 0 && at == nil {
		return l.newFirstElem()
	}

	l.m.Lock()
	defer l.m.Unlock()

	if l != at.list {
		return nil
	}

	if l.Freed == nil {
		e = l.getElemData(l.Used_idx)
		l.Used_idx += 1
	} else {
		e = l.Freed
		e.prev = nil
		e.next = nil
		if l.Freed.next == nil {
			l.Freed = nil
		} else {
			l.Freed = l.Freed.next
			l.Freed.prev = nil
		}
	}
	e.list = l
	n := at.next
	at.next = e
	e.prev = at
	if n != nil {
		n.prev = e
		e.next = n
	} else {
		e.list.Used.prev = e
	}

	l.Len++
	return e
}

func (l *List) Init(first_value interface{}, value_len int) *List {
	l.m.Lock()
	defer l.m.Unlock()
	if l.Used == nil {
		var buf_len int64
		if value_len < 1024 {
			buf_len = int64(DEFAULT_BUF_SIZE)
		} else {
			buf_len = int64(value_len)
		}
		l.Value_inf = first_value
		l.SizeData = int64(reflect.TypeOf(first_value).Size())
		l.SizeElm = int64(reflect.TypeOf(Element{}).Size())
		l.elms = make([]byte, buf_len*l.SizeElm,
			buf_len*l.SizeElm)
		l.datas = make([]byte, buf_len*l.SizeData,
			buf_len*l.SizeData)
		elm := (*Element)(unsafe.Pointer(&l.elms[0]))
		elm.value = unsafe.Pointer(&l.datas[0])
		elm.prev = elm
		elm.next = nil
		elm.list = l
		l.Used = elm
		l.Freed = nil
		l.Used_idx = 1
		l.Len = 1
	}
	return l
}

func (l *List) Front() *Element {
	return l.Used
}

func (l *List) Back() *Element {
	if l.Used == nil {
		return nil
	} else {
		return l.Used.prev
	}
}

func (l *List) Inf() interface{} {
	return l.Value_inf
}

func (l *List) Value() unsafe.Pointer {
	return l.Used.value
}
func (l *List) SetCastFunc(f func(val unsafe.Pointer) interface{}) {
	l.cast_f = f
}

func (e *Element) List() *List {
	return e.list
}

func (e *Element) ValueWithCast() interface{} {
	return e.list.cast_f(e.Value())
}
<|endoftext|>


<commit_before>package tarutil

import (
	"bytes"
	"io"
	"os"
	"path"
	"path/filepath"

	"github.com/pachyderm/pachyderm/src/client/pkg/errors"
	"github.com/pachyderm/pachyderm/src/server/pkg/tar"
)

type File interface {
	Header() (*tar.Header, error)
	Content(io.Writer) error
}

type file struct {
	hdr  *tar.Header
	data []byte
}

func NewFile(name string, data []byte) File {
	return newFile(NewHeader(name, int64(len(data))), data)
}

func newFile(hdr *tar.Header, data []byte) File {
	return &file{
		hdr:  hdr,
		data: data,
	}
}

func NewHeader(name string, size int64) *tar.Header {
	return &tar.Header{
		Name: name,
		Size: size,
	}
}

func (f *file) Header() (*tar.Header, error) {
	return f.hdr, nil
}

func (f *file) Content(w io.Writer) error {
	_, err := w.Write(f.data)
	return err
}

func WriteFile(tw *tar.Writer, file File) error {
	hdr, err := file.Header()
	if err != nil {
		return err
	}
	if err := tw.WriteHeader(hdr); err != nil {
		return err
	}
	if err := file.Content(tw); err != nil {
		return err
	}
	return tw.Flush()
}

func WithWriter(w io.Writer, cb func(*tar.Writer) error) (retErr error) {
	tw := tar.NewWriter(w)
	defer func() {
		if retErr == nil {
			retErr = tw.Close()
		}
	}()
	return cb(tw)
}

func Iterate(r io.Reader, cb func(File) error) error {
	tr := tar.NewReader(r)
	for {
		hdr, err := tr.Next()
		if err != nil {
			if errors.Is(err, io.EOF) {
				return nil
			}
			return err
		}
		buf := &bytes.Buffer{}
		_, err = io.Copy(buf, tr)
		if err != nil {
			return err
		}
		if err := cb(newFile(hdr, buf.Bytes())); err != nil {
			return err
		}
	}
}

func Equal(file1, file2 File) (bool, error) {
	buf1, buf2 := &bytes.Buffer{}, &bytes.Buffer{}
	tw1, tw2 := tar.NewWriter(buf1), tar.NewWriter(buf2)
	if err := WriteFile(tw1, file1); err != nil {
		return false, err
	}
	if err := WriteFile(tw2, file2); err != nil {
		return false, err
	}
	if !bytes.Equal(buf1.Bytes(), buf2.Bytes()) {
		return false, nil
	}
	return true, nil
}

func TarToLocal(storageRoot string, r io.Reader) error {
	tr := tar.NewReader(r)
	for {
		hdr, err := tr.Next()
		if err != nil {
			if errors.Is(err, io.EOF) {
				return nil
			}
			return err
		}
		// TODO: Use the tar header metadata.
		fullPath := path.Join(storageRoot, hdr.Name)
		if hdr.Typeflag == tar.TypeDir {
			if err := os.MkdirAll(fullPath, 0700); err != nil {
				return err
			}
			continue
		}
		if err := writeFile(fullPath, tr); err != nil {
			return err
		}
	}
}

func writeFile(filePath string, r io.Reader) (retErr error) {
	if err := os.MkdirAll(path.Dir(filePath), 0700); err != nil {
		return err
	}
	f, err := os.Create(filePath)
	if err != nil {
		return err
	}
	defer func() {
		if err := f.Close(); retErr == nil {
			retErr = err
		}
	}()
	_, err = io.Copy(f, r)
	return err
}

func LocalToTar(storageRoot string, w io.Writer) {
	return WithWriter(w, func(tw *tar.Writer) error {
		return filepath.Walk(storageRoot, func(file string, fi os.FileInfo, err error) (retErr error) {
			if err != nil {
				return err
			}
			if file == storageRoot {
				return nil
			}
			// TODO: link name?
			hdr, err := tar.FileInfoHeader(fi, "")
			if err != nil {
				return err
			}
			hdr.Name, err = filepath.Rel(storageRoot, file)
			if err != nil {
				return err
			}
			// TODO: Remove when path cleaning is in.
			hdr.Name = filepath.Join("/", hdr.Name)
			if err := tw.WriteHeader(hdr); err != nil {
				return err
			}
			if hdr.Typeflag == tar.TypeDir {
				return nil
			}
			f, err := os.Open(file)
			if err != nil {
				return err
			}
			defer func() {
				if err := f.Close(); retErr == nil {
					retErr = err
				}
			}()
			_, err = io.Copy(tw, f)
			return err
		})
	})
}
<commit_msg>Whoops<commit_after>package tarutil

import (
	"bytes"
	"io"
	"os"
	"path"
	"path/filepath"

	"github.com/pachyderm/pachyderm/src/client/pkg/errors"
	"github.com/pachyderm/pachyderm/src/server/pkg/tar"
)

type File interface {
	Header() (*tar.Header, error)
	Content(io.Writer) error
}

type file struct {
	hdr  *tar.Header
	data []byte
}

func NewFile(name string, data []byte) File {
	return newFile(NewHeader(name, int64(len(data))), data)
}

func newFile(hdr *tar.Header, data []byte) File {
	return &file{
		hdr:  hdr,
		data: data,
	}
}

func NewHeader(name string, size int64) *tar.Header {
	return &tar.Header{
		Name: name,
		Size: size,
	}
}

func (f *file) Header() (*tar.Header, error) {
	return f.hdr, nil
}

func (f *file) Content(w io.Writer) error {
	_, err := w.Write(f.data)
	return err
}

func WriteFile(tw *tar.Writer, file File) error {
	hdr, err := file.Header()
	if err != nil {
		return err
	}
	if err := tw.WriteHeader(hdr); err != nil {
		return err
	}
	if err := file.Content(tw); err != nil {
		return err
	}
	return tw.Flush()
}

func WithWriter(w io.Writer, cb func(*tar.Writer) error) (retErr error) {
	tw := tar.NewWriter(w)
	defer func() {
		if retErr == nil {
			retErr = tw.Close()
		}
	}()
	return cb(tw)
}

func Iterate(r io.Reader, cb func(File) error) error {
	tr := tar.NewReader(r)
	for {
		hdr, err := tr.Next()
		if err != nil {
			if errors.Is(err, io.EOF) {
				return nil
			}
			return err
		}
		buf := &bytes.Buffer{}
		_, err = io.Copy(buf, tr)
		if err != nil {
			return err
		}
		if err := cb(newFile(hdr, buf.Bytes())); err != nil {
			return err
		}
	}
}

func Equal(file1, file2 File) (bool, error) {
	buf1, buf2 := &bytes.Buffer{}, &bytes.Buffer{}
	tw1, tw2 := tar.NewWriter(buf1), tar.NewWriter(buf2)
	if err := WriteFile(tw1, file1); err != nil {
		return false, err
	}
	if err := WriteFile(tw2, file2); err != nil {
		return false, err
	}
	if !bytes.Equal(buf1.Bytes(), buf2.Bytes()) {
		return false, nil
	}
	return true, nil
}

func TarToLocal(storageRoot string, r io.Reader) error {
	tr := tar.NewReader(r)
	for {
		hdr, err := tr.Next()
		if err != nil {
			if errors.Is(err, io.EOF) {
				return nil
			}
			return err
		}
		// TODO: Use the tar header metadata.
		fullPath := path.Join(storageRoot, hdr.Name)
		if hdr.Typeflag == tar.TypeDir {
			if err := os.MkdirAll(fullPath, 0700); err != nil {
				return err
			}
			continue
		}
		if err := writeFile(fullPath, tr); err != nil {
			return err
		}
	}
}

func writeFile(filePath string, r io.Reader) (retErr error) {
	if err := os.MkdirAll(path.Dir(filePath), 0700); err != nil {
		return err
	}
	f, err := os.Create(filePath)
	if err != nil {
		return err
	}
	defer func() {
		if err := f.Close(); retErr == nil {
			retErr = err
		}
	}()
	_, err = io.Copy(f, r)
	return err
}

func LocalToTar(storageRoot string, w io.Writer) error {
	return WithWriter(w, func(tw *tar.Writer) error {
		return filepath.Walk(storageRoot, func(file string, fi os.FileInfo, err error) (retErr error) {
			if err != nil {
				return err
			}
			if file == storageRoot {
				return nil
			}
			// TODO: link name?
			hdr, err := tar.FileInfoHeader(fi, "")
			if err != nil {
				return err
			}
			hdr.Name, err = filepath.Rel(storageRoot, file)
			if err != nil {
				return err
			}
			// TODO: Remove when path cleaning is in.
			hdr.Name = filepath.Join("/", hdr.Name)
			if err := tw.WriteHeader(hdr); err != nil {
				return err
			}
			if hdr.Typeflag == tar.TypeDir {
				return nil
			}
			f, err := os.Open(file)
			if err != nil {
				return err
			}
			defer func() {
				if err := f.Close(); retErr == nil {
					retErr = err
				}
			}()
			_, err = io.Copy(tw, f)
			return err
		})
	})
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors.

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 configmap

// This file tests use of the configMap API resource.

import (
	"context"
	"testing"

	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	clientset "k8s.io/client-go/kubernetes"
	restclient "k8s.io/client-go/rest"
	"k8s.io/kubernetes/test/integration"
	"k8s.io/kubernetes/test/integration/framework"
)

// TestConfigMap tests apiserver-side behavior of creation of ConfigMaps and pods that consume them.
func TestConfigMap(t *testing.T) {
	_, s, closeFn := framework.RunAnAPIServer(nil)
	defer closeFn()

	client := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"}}})

	ns := framework.CreateTestingNamespace("config-map", t)
	defer framework.DeleteTestingNamespace(ns, t)

	DoTestConfigMap(t, client, ns)
}

func DoTestConfigMap(t *testing.T, client clientset.Interface, ns *v1.Namespace) {
	cfg := v1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "configmap",
			Namespace: ns.Name,
		},
		Data: map[string]string{
			"data-1": "value-1",
			"data-2": "value-2",
			"data-3": "value-3",
		},
	}

	if _, err := client.CoreV1().ConfigMaps(cfg.Namespace).Create(context.TODO(), &cfg, metav1.CreateOptions{}); err != nil {
		t.Errorf("unable to create test configMap: %v", err)
	}
	defer deleteConfigMapOrErrorf(t, client, cfg.Namespace, cfg.Name)

	pod := &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "XXX",
			Namespace: ns.Name,
		},
		Spec: v1.PodSpec{
			Containers: []v1.Container{
				{
					Name:  "fake-name",
					Image: "fakeimage",
					Env: []v1.EnvVar{
						{
							Name: "CONFIG_DATA_1",
							ValueFrom: &v1.EnvVarSource{
								ConfigMapKeyRef: &v1.ConfigMapKeySelector{
									LocalObjectReference: v1.LocalObjectReference{
										Name: "configmap",
									},
									Key: "data-1",
								},
							},
						},
						{
							Name: "CONFIG_DATA_2",
							ValueFrom: &v1.EnvVarSource{
								ConfigMapKeyRef: &v1.ConfigMapKeySelector{
									LocalObjectReference: v1.LocalObjectReference{
										Name: "configmap",
									},
									Key: "data-2",
								},
							},
						}, {
							Name: "CONFIG_DATA_3",
							ValueFrom: &v1.EnvVarSource{
								ConfigMapKeyRef: &v1.ConfigMapKeySelector{
									LocalObjectReference: v1.LocalObjectReference{
										Name: "configmap",
									},
									Key: "data-3",
								},
							},
						},
					},
				},
			},
		},
	}

	pod.ObjectMeta.Name = "uses-configmap"
	if _, err := client.CoreV1().Pods(ns.Name).Create(context.TODO(), pod, metav1.CreateOptions{}); err != nil {
		t.Errorf("Failed to create pod: %v", err)
	}
	defer integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
}

func deleteConfigMapOrErrorf(t *testing.T, c clientset.Interface, ns, name string) {
	if err := c.CoreV1().ConfigMaps(ns).Delete(context.TODO(), name, metav1.DeleteOptions{}); err != nil {
		t.Errorf("unable to delete ConfigMap %v: %v", name, err)
	}
}
<commit_msg>Clean shutdown of configmap integration tests<commit_after>/*
Copyright 2015 The Kubernetes Authors.

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 configmap

// This file tests use of the configMap API resource.

import (
	"context"
	"testing"

	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	clientset "k8s.io/client-go/kubernetes"
	kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
	"k8s.io/kubernetes/test/integration"
	"k8s.io/kubernetes/test/integration/framework"
)

// TestConfigMap tests apiserver-side behavior of creation of ConfigMaps and pods that consume them.
func TestConfigMap(t *testing.T) {
	// Disable ServiceAccount admission plugin as we don't have serviceaccount controller running.
	server := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins=ServiceAccount"}, framework.SharedEtcd())
	defer server.TearDownFn()

	client := clientset.NewForConfigOrDie(server.ClientConfig)

	ns := framework.CreateNamespaceOrDie(client, "config-map", t)
	defer framework.DeleteNamespaceOrDie(client, ns, t)

	DoTestConfigMap(t, client, ns)
}

func DoTestConfigMap(t *testing.T, client clientset.Interface, ns *v1.Namespace) {
	cfg := v1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "configmap",
			Namespace: ns.Name,
		},
		Data: map[string]string{
			"data-1": "value-1",
			"data-2": "value-2",
			"data-3": "value-3",
		},
	}

	if _, err := client.CoreV1().ConfigMaps(cfg.Namespace).Create(context.TODO(), &cfg, metav1.CreateOptions{}); err != nil {
		t.Errorf("unable to create test configMap: %v", err)
	}
	defer deleteConfigMapOrErrorf(t, client, cfg.Namespace, cfg.Name)

	pod := &v1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "XXX",
			Namespace: ns.Name,
		},
		Spec: v1.PodSpec{
			Containers: []v1.Container{
				{
					Name:  "fake-name",
					Image: "fakeimage",
					Env: []v1.EnvVar{
						{
							Name: "CONFIG_DATA_1",
							ValueFrom: &v1.EnvVarSource{
								ConfigMapKeyRef: &v1.ConfigMapKeySelector{
									LocalObjectReference: v1.LocalObjectReference{
										Name: "configmap",
									},
									Key: "data-1",
								},
							},
						},
						{
							Name: "CONFIG_DATA_2",
							ValueFrom: &v1.EnvVarSource{
								ConfigMapKeyRef: &v1.ConfigMapKeySelector{
									LocalObjectReference: v1.LocalObjectReference{
										Name: "configmap",
									},
									Key: "data-2",
								},
							},
						}, {
							Name: "CONFIG_DATA_3",
							ValueFrom: &v1.EnvVarSource{
								ConfigMapKeyRef: &v1.ConfigMapKeySelector{
									LocalObjectReference: v1.LocalObjectReference{
										Name: "configmap",
									},
									Key: "data-3",
								},
							},
						},
					},
				},
			},
		},
	}

	pod.ObjectMeta.Name = "uses-configmap"
	if _, err := client.CoreV1().Pods(ns.Name).Create(context.TODO(), pod, metav1.CreateOptions{}); err != nil {
		t.Errorf("Failed to create pod: %v", err)
	}
	defer integration.DeletePodOrErrorf(t, client, ns.Name, pod.Name)
}

func deleteConfigMapOrErrorf(t *testing.T, c clientset.Interface, ns, name string) {
	if err := c.CoreV1().ConfigMaps(ns).Delete(context.TODO(), name, metav1.DeleteOptions{}); err != nil {
		t.Errorf("unable to delete ConfigMap %v: %v", name, err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 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 drive

import (
	"errors"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/cheggaaa/pb"
	"github.com/odeke-em/drive/config"
	"github.com/odeke-em/log"
)

var (
	ErrNoContext = errors.New("not in a drive context")
)

const (
	DriveIgnoreSuffix = ".driveignore"
)

type Options struct {
	// Depth is the number of pages/ listing recursion depth
	Depth int
	// Exports contains the formats to export your Google Docs + Sheets to
	// e.g ["csv" "txt"]
	Exports []string
	// Directory to put the exported Google Docs + Sheets, if not
	// provided will export them to the same dir as the source files are.
	ExportsDir string
	// Force once set always converts NoChange into an Addition
	Force bool
	// Hidden discovers hidden paths if set
	Hidden       bool
	IgnoreRegexp *regexp.Regexp
	// IgnoreChecksum when set avoids the step
	// of comparing checksums as a final check.
	IgnoreChecksum bool
	// IgnoreConflict when set turns off the conflict resolution safety.
	IgnoreConflict bool
	// Allows listing of content in trash
	InTrash bool
	Meta    *map[string][]string
	Mount   *config.Mount
	// NoClobber when set prevents overwriting of stale content
	NoClobber bool
	// NoPrompt overwrites any prompt pauses
	NoPrompt bool
	Path     string
	// PageSize determines the number of results returned per API call
	PageSize  int64
	Recursive bool
	// Sources is a of list all paths that are
	// within the scope/path of the current gd context
	Sources []string
	// TypeMask contains the result of setting different type bits e.g
	// Folder to search only for folders etc.
	TypeMask int
	// Piped when set means to infer content to or from stdin
	Piped bool
	// Quiet when set toggles only logging of errors to stderrs as
	// well as reading from stdin in this case stdout is not logged to
	Quiet bool
}

type Commands struct {
	context *config.Context
	rem     *Remote
	opts    *Options
	log     *log.Logger

	progress *pb.ProgressBar
}

func New(context *config.Context, opts *Options) *Commands {
	var r *Remote
	if context != nil {
		r = NewRemoteContext(context)
	}
	if opts != nil {
		// should always start with /
		opts.Path = path.Clean(path.Join("/", opts.Path))

		if !opts.Force {
			ignoresPath := filepath.Join(context.AbsPath, DriveIgnoreSuffix)
			opts.IgnoreRegexp = readCommentedFileCompileRegexp(ignoresPath)
		}
	}

	stdin, stdout, stderr := os.Stdin, os.Stdout, os.Stderr
	if opts.Quiet {
		stdout = nil
	}
	return &Commands{
		context: context,
		rem:     r,
		opts:    opts,
		log:     log.New(stdin, stdout, stderr),
	}
}

func readCommentedFileCompileRegexp(p string) *regexp.Regexp {
	clauses, err := readCommentedFile(p, "#")
	if err != nil {
		return nil
	}
	regExComp, regErr := regexp.Compile(strings.Join(clauses, "|"))
	if regErr != nil {
		return nil
	}
	return regExComp
}

func (g *Commands) taskStart(numOfTasks int) {
	if numOfTasks > 0 {
		g.progress = pb.StartNew(numOfTasks)
	}
}

func (g *Commands) taskDone() {
	if g.progress != nil {
		g.progress.Increment()
	}
}

func (g *Commands) taskFinish() {
	if g.progress != nil {
		g.progress.Finish()
	}
}
<commit_msg>don't dereference Opts if nil<commit_after>// Copyright 2013 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 drive

import (
	"errors"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/cheggaaa/pb"
	"github.com/odeke-em/drive/config"
	"github.com/odeke-em/log"
)

var (
	ErrNoContext = errors.New("not in a drive context")
)

const (
	DriveIgnoreSuffix = ".driveignore"
)

type Options struct {
	// Depth is the number of pages/ listing recursion depth
	Depth int
	// Exports contains the formats to export your Google Docs + Sheets to
	// e.g ["csv" "txt"]
	Exports []string
	// Directory to put the exported Google Docs + Sheets, if not
	// provided will export them to the same dir as the source files are.
	ExportsDir string
	// Force once set always converts NoChange into an Addition
	Force bool
	// Hidden discovers hidden paths if set
	Hidden       bool
	IgnoreRegexp *regexp.Regexp
	// IgnoreChecksum when set avoids the step
	// of comparing checksums as a final check.
	IgnoreChecksum bool
	// IgnoreConflict when set turns off the conflict resolution safety.
	IgnoreConflict bool
	// Allows listing of content in trash
	InTrash bool
	Meta    *map[string][]string
	Mount   *config.Mount
	// NoClobber when set prevents overwriting of stale content
	NoClobber bool
	// NoPrompt overwrites any prompt pauses
	NoPrompt bool
	Path     string
	// PageSize determines the number of results returned per API call
	PageSize  int64
	Recursive bool
	// Sources is a of list all paths that are
	// within the scope/path of the current gd context
	Sources []string
	// TypeMask contains the result of setting different type bits e.g
	// Folder to search only for folders etc.
	TypeMask int
	// Piped when set means to infer content to or from stdin
	Piped bool
	// Quiet when set toggles only logging of errors to stderrs as
	// well as reading from stdin in this case stdout is not logged to
	Quiet bool
}

type Commands struct {
	context *config.Context
	rem     *Remote
	opts    *Options
	log     *log.Logger

	progress *pb.ProgressBar
}

func New(context *config.Context, opts *Options) *Commands {
	var r *Remote
	if context != nil {
		r = NewRemoteContext(context)
	}

	stdin, stdout, stderr := os.Stdin, os.Stdout, os.Stderr

	if opts != nil {
		// should always start with /
		opts.Path = path.Clean(path.Join("/", opts.Path))

		if !opts.Force {
			ignoresPath := filepath.Join(context.AbsPath, DriveIgnoreSuffix)
			opts.IgnoreRegexp = readCommentedFileCompileRegexp(ignoresPath)
		}

                if opts.Quiet {
                        stdout = nil
                }
	}

	return &Commands{
		context: context,
		rem:     r,
		opts:    opts,
		log:     log.New(stdin, stdout, stderr),
	}
}

func readCommentedFileCompileRegexp(p string) *regexp.Regexp {
	clauses, err := readCommentedFile(p, "#")
	if err != nil {
		return nil
	}
	regExComp, regErr := regexp.Compile(strings.Join(clauses, "|"))
	if regErr != nil {
		return nil
	}
	return regExComp
}

func (g *Commands) taskStart(numOfTasks int) {
	if numOfTasks > 0 {
		g.progress = pb.StartNew(numOfTasks)
	}
}

func (g *Commands) taskDone() {
	if g.progress != nil {
		g.progress.Increment()
	}
}

func (g *Commands) taskFinish() {
	if g.progress != nil {
		g.progress.Finish()
	}
}
<|endoftext|>


<commit_before>package upgradetest

import (
	"fmt"
	"math/rand"
	"testing"

	"github.com/coreos-inc/vault-operator/test/e2e/e2eutil"
	"github.com/coreos-inc/vault-operator/test/e2e/upgradetest/framework"
)

func newOperatorName() string {
	suffix := fmt.Sprintf("-%d", rand.Uint64())
	return "vault-operator" + suffix
}

func TestUpgradeAndScaleVault(t *testing.T) {
	f := framework.Global
	name := newOperatorName()
	err := f.CreateOperatorDeployment(name)
	if err != nil {
		t.Fatal("failed to create vault operator: %v", err)
	}
	defer func() {
		err := f.DeleteOperatorDeployment(name)
		if err != nil {
			t.Fatal("failed to delete vault operator: %v", err)
		}
	}()
	if err = e2eutil.WaitUntilOperatorReady(f.KubeClient, f.Namespace, name); err != nil {
		t.Fatalf("failed to wait for operator to become ready: %v", err)
	}

	vaultCR, err := e2eutil.CreateCluster(t, f.VaultsCRClient, e2eutil.NewCluster("upgradetest-vault-", f.Namespace, 1))
	if err != nil {
		t.Fatalf("failed to create vault cluster: %v", err)
	}
	defer func() {
		if err := e2eutil.DeleteCluster(t, f.VaultsCRClient, vaultCR); err != nil {
			t.Fatalf("failed to delete vault cluster: %v", err)
		}
	}()
	vaultCR, tlsConfig := e2eutil.WaitForCluster(t, f.KubeClient, f.VaultsCRClient, vaultCR)

	startingConns, err := e2eutil.PortForwardVaultClients(f.KubeClient, f.Config, f.Namespace, tlsConfig, vaultCR.Status.AvailableNodes...)
	if err != nil {
		t.Fatalf("failed to portforward and create vault clients: %v", err)
	}
	defer e2eutil.CleanupConnections(t, f.Namespace, startingConns)

	// Init vault via the first available node
	podName := vaultCR.Status.AvailableNodes[0]
	conn := e2eutil.GetConnOrFail(t, podName, startingConns)
	vaultCR, initResp := e2eutil.InitializeVault(t, f.VaultsCRClient, vaultCR, conn)

	// Unseal the vault node and wait for it to become active
	podName = vaultCR.Status.SealedNodes[0]
	conn = e2eutil.GetConnOrFail(t, podName, startingConns)
	if err := e2eutil.UnsealVaultNode(initResp.Keys[0], conn); err != nil {
		t.Fatalf("failed to unseal vault node(%v): %v", podName, err)
	}
	vaultCR, err = e2eutil.WaitActiveVaultsUp(t, f.VaultsCRClient, 6, vaultCR)
	if err != nil {
		t.Fatalf("failed to wait for any node to become active: %v", err)
	}

	// TODO: Upgrade the operator and try to scale the cluster
}
<commit_msg>upgradetest: complete TestUpgradeAndScale<commit_after>package upgradetest

import (
	"fmt"
	"math/rand"
	"testing"

	"github.com/coreos-inc/vault-operator/test/e2e/e2eutil"
	"github.com/coreos-inc/vault-operator/test/e2e/upgradetest/framework"
)

func newOperatorName() string {
	suffix := fmt.Sprintf("-%d", rand.Uint64())
	return "vault-operator" + suffix
}

func TestUpgradeAndScaleVault(t *testing.T) {
	f := framework.Global
	name := newOperatorName()
	err := f.CreateOperatorDeployment(name)
	if err != nil {
		t.Fatal("failed to create vault operator: %v", err)
	}
	defer func() {
		err := f.DeleteOperatorDeployment(name)
		if err != nil {
			t.Fatal("failed to delete vault operator: %v", err)
		}
	}()
	if err = e2eutil.WaitUntilOperatorReady(f.KubeClient, f.Namespace, name); err != nil {
		t.Fatalf("failed to wait for operator to become ready: %v", err)
	}

	vaultCR, err := e2eutil.CreateCluster(t, f.VaultsCRClient, e2eutil.NewCluster("upgradetest-vault-", f.Namespace, 1))
	if err != nil {
		t.Fatalf("failed to create vault cluster: %v", err)
	}
	defer func() {
		if err := e2eutil.DeleteCluster(t, f.VaultsCRClient, vaultCR); err != nil {
			t.Fatalf("failed to delete vault cluster: %v", err)
		}
	}()
	vaultCR, tlsConfig := e2eutil.WaitForCluster(t, f.KubeClient, f.VaultsCRClient, vaultCR)

	startingConns, err := e2eutil.PortForwardVaultClients(f.KubeClient, f.Config, f.Namespace, tlsConfig, vaultCR.Status.AvailableNodes...)
	if err != nil {
		t.Fatalf("failed to portforward and create vault clients: %v", err)
	}
	defer e2eutil.CleanupConnections(t, f.Namespace, startingConns)

	// Init vault via the first available node
	podName := vaultCR.Status.AvailableNodes[0]
	conn := e2eutil.GetConnOrFail(t, podName, startingConns)
	vaultCR, initResp := e2eutil.InitializeVault(t, f.VaultsCRClient, vaultCR, conn)

	// Unseal the vault node and wait for it to become active
	podName = vaultCR.Status.SealedNodes[0]
	conn = e2eutil.GetConnOrFail(t, podName, startingConns)
	if err := e2eutil.UnsealVaultNode(initResp.Keys[0], conn); err != nil {
		t.Fatalf("failed to unseal vault node(%v): %v", podName, err)
	}
	vaultCR, err = e2eutil.WaitActiveVaultsUp(t, f.VaultsCRClient, 6, vaultCR)
	if err != nil {
		t.Fatalf("failed to wait for any node to become active: %v", err)
	}

	if err = f.UpgradeOperator(name); err != nil {
		t.Fatalf("failed to upgrade operator: %v", err)
	}

	// Resize cluster to 2 nodes
	vaultCR, err = e2eutil.ResizeCluster(t, f.VaultsCRClient, vaultCR, 2)
	if err != nil {
		t.Fatalf("failed to resize vault cluster: %v", err)
	}

	// Wait for 1 unsealed node and create a vault client for it
	vaultCR, err = e2eutil.WaitSealedVaultsUp(t, f.VaultsCRClient, 1, 6, vaultCR)
	if err != nil {
		t.Fatalf("failed to wait for vault nodes to become sealed: %v", err)
	}
	podName = vaultCR.Status.SealedNodes[0]
	scaledConns, err := e2eutil.PortForwardVaultClients(f.KubeClient, f.Config, f.Namespace, tlsConfig, podName)
	if err != nil {
		t.Fatalf("failed to portforward and create vault clients: %v", err)
	}
	defer e2eutil.CleanupConnections(t, f.Namespace, scaledConns)

	// Unseal the new node and wait for it to become standby
	conn = e2eutil.GetConnOrFail(t, podName, scaledConns)
	if err := e2eutil.UnsealVaultNode(initResp.Keys[0], conn); err != nil {
		t.Fatalf("failed to unseal vault node(%v): %v", podName, err)
	}
	vaultCR, err = e2eutil.WaitStandbyVaultsUp(t, f.VaultsCRClient, 1, 6, vaultCR)
	if err != nil {
		t.Fatalf("failed to wait for vault nodes to become standby: %v", err)
	}
}
<|endoftext|>


<commit_before>package engi

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestCameraMoveX(t *testing.T) {
	cam := &cameraSystem{}
	cam.New()
	WorldBounds = AABB{Point{0, 0}, Point{300, 300}}

	currentX := cam.X()

	cam.moveY(0.50)
	assert.Equal(t, cam.X(), currentX, "Moving in the Y direction shouldn't change the X location")

	cam.moveY(-1)
	assert.Equal(t, cam.X(), currentX, "Moving in the Y direction shouldn't change the X location")

	cam.zoom(0.50)
	assert.Equal(t, cam.X(), currentX, "Zooming in should not change the X location")

	cam.zoom(-1)
	assert.Equal(t, cam.X(), currentX, "Zooming out should not change the X location")

	cam.moveX(10)
	assert.Equal(t, cam.X(), currentX+10, "Moving by 10 units, should have moved the camera by 10 units")

	cam.moveX(-10)
	assert.Equal(t, cam.X(), currentX, "Moving by -10 units, should have moved the camera back by 10 units")

	cam.moveX(305)
	assert.Equal(t, cam.X(), WorldBounds.Max.X, "Moving too many unit, should have moved the camera to the maximum")

	cam.moveX(-305)
	assert.Equal(t, cam.X(), WorldBounds.Min.X, "Moving too many units back, should have moved the camera to the minimum")
}

func TestCameraMoveY(t *testing.T) {
	cam := &cameraSystem{}
	cam.New()
	WorldBounds = AABB{Point{0, 0}, Point{300, 300}}

	currentY := cam.Y()

	cam.moveX(0.50)
	assert.Equal(t, cam.Y(), currentY, "Moving in the X direction shouldn't change the Y location")

	cam.moveX(-1)
	assert.Equal(t, cam.Y(), currentY, "Moving in the X direction shouldn't change the Y location")

	cam.zoom(0.50)
	assert.Equal(t, cam.Y(), currentY, "Zooming in should not change the Y location")

	cam.zoom(-1)
	assert.Equal(t, cam.Y(), currentY, "Zooming out should not change the Y location")

	cam.moveY(10)
	assert.Equal(t, cam.Y(), currentY+10, "Moving by 10 units, should have moved the camera by 10 units")

	cam.moveY(-10)
	assert.Equal(t, cam.Y(), currentY, "Moving by -10 units, should have moved the camera back by 10 units")

	cam.moveY(305)
	assert.Equal(t, cam.Y(), WorldBounds.Max.Y, "Moving too many unit, should have moved the camera to the maximum")

	cam.moveY(-305)
	assert.Equal(t, cam.Y(), WorldBounds.Min.Y, "Moving too many units back, should have moved the camera to the minimum")
}

func TestCameraZoom(t *testing.T) {
	cam := &cameraSystem{}
	cam.New()

	currentZ := cam.Z()

	cam.moveX(0.5)
	assert.Equal(t, cam.Z(), currentZ, "Moving in the X direction shouldn't change the zoom level")

	cam.moveX(-1)
	assert.Equal(t, cam.Z(), currentZ, "Moving in the X direction shouldn't change the zoom level")

	cam.moveY(0.5)
	assert.Equal(t, cam.Z(), currentZ, "Moving in the Y direction shouldn't change the zoom level")

	cam.moveY(-1)
	assert.Equal(t, cam.Z(), currentZ, "Moving in the Y direction shouldn't change the zoom level")

	cam.zoom(0.5)
	assert.Equal(t, cam.Z(), currentZ+0.5, "Should be zoomed in an additional 0.5")

	cam.zoom(-0.5)
	assert.Equal(t, cam.Z(), currentZ, "Should be zoomed out to the starting zoom level")

	cam.zoom(-1000)
	assert.Equal(t, cam.Z(), MinZoom, "Should be zoomed out to the minimum zoom level")

	cam.zoom(1000)
	assert.Equal(t, cam.Z(), MaxZoom, "Should be zoomed in to the maximum zoom level")
}

func TestCameraMoveToX(t *testing.T) {
	cam := &cameraSystem{}
	cam.New()
	WorldBounds = AABB{Point{0, 0}, Point{300, 300}}

	currentX := cam.X()

	cam.moveToX(currentX + 5)
	assert.Equal(t, cam.X(), currentX+5, "Moving to current + 5 should get us to current + 5")

	cam.moveToX(600)
	assert.Equal(t, cam.X(), WorldBounds.Max.X, "Moving to a location out of bounds, should get us to the maximum")

	cam.moveToX(-10)
	assert.Equal(t, cam.X(), WorldBounds.Min.X, "Moving to a location out of bounds, should get us to the minimum")
}

func TestCameraMoveToY(t *testing.T) {
	cam := &cameraSystem{}
	cam.New()
	WorldBounds = AABB{Point{0, 0}, Point{300, 300}}

	currentY := cam.Y()

	cam.moveToY(currentY + 5)
	assert.Equal(t, cam.Y(), currentY+5, "Moving to current + 5 should get us to current + 5")

	cam.moveToY(600)
	assert.Equal(t, cam.Y(), WorldBounds.Max.Y, "Moving to a location out of bounds, should get us to the maximum")

	cam.moveToY(-10)
	assert.Equal(t, cam.Y(), WorldBounds.Min.Y, "Moving to a location out of bounds, should get us to the minimum")
}

func TestCameraZoomTo(t *testing.T) {
	cam := &cameraSystem{}
	cam.New()

	currentZ := cam.Z()

	cam.zoomTo(currentZ + 5)
	assert.Equal(t, cam.Z(), currentZ+5, "Zooming to current + 5 should get us to current + 5")

	cam.zoomTo(600)
	assert.Equal(t, cam.Z(), MaxZoom, "Zooming too close, should get us to the minimum distance")

	cam.zoomTo(-10)
	assert.Equal(t, cam.Z(), MinZoom, "Zooming too far, should get us to the maximum distance")
}
<commit_msg>Fixed camera test bug<commit_after>package engi

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestCameraMoveX(t *testing.T) {
	cam := &cameraSystem{}
	cam.New()
	WorldBounds = AABB{Point{0, 0}, Point{300, 300}}

	currentX := cam.X()

	cam.moveY(0.50)
	assert.Equal(t, cam.X(), currentX, "Moving in the Y direction shouldn't change the X location")

	cam.moveY(-1)
	assert.Equal(t, cam.X(), currentX, "Moving in the Y direction shouldn't change the X location")

	cam.zoom(0.50)
	assert.Equal(t, cam.X(), currentX, "Zooming in should not change the X location")

	cam.zoom(-1)
	assert.Equal(t, cam.X(), currentX, "Zooming out should not change the X location")

	cam.moveX(10)
	assert.Equal(t, cam.X(), currentX+10, "Moving by 10 units, should have moved the camera by 10 units")

	cam.moveX(-10)
	assert.Equal(t, cam.X(), currentX, "Moving by -10 units, should have moved the camera back by 10 units")

	cam.moveX(305)
	assert.Equal(t, cam.X(), WorldBounds.Max.X, "Moving too many unit, should have moved the camera to the maximum")

	cam.moveX(-305)
	assert.Equal(t, cam.X(), WorldBounds.Min.X, "Moving too many units back, should have moved the camera to the minimum")
}

func TestCameraMoveY(t *testing.T) {
	cam := &cameraSystem{}
	cam.New()
	WorldBounds = AABB{Point{0, 0}, Point{300, 300}}

	currentY := cam.Y()

	cam.moveX(0.50)
	assert.Equal(t, cam.Y(), currentY, "Moving in the X direction shouldn't change the Y location")

	cam.moveX(-1)
	assert.Equal(t, cam.Y(), currentY, "Moving in the X direction shouldn't change the Y location")

	cam.zoom(0.50)
	assert.Equal(t, cam.Y(), currentY, "Zooming in should not change the Y location")

	cam.zoom(-1)
	assert.Equal(t, cam.Y(), currentY, "Zooming out should not change the Y location")

	cam.moveY(10)
	assert.Equal(t, cam.Y(), currentY+10, "Moving by 10 units, should have moved the camera by 10 units")

	cam.moveY(-10)
	assert.Equal(t, cam.Y(), currentY, "Moving by -10 units, should have moved the camera back by 10 units")

	cam.moveY(305)
	assert.Equal(t, cam.Y(), WorldBounds.Max.Y, "Moving too many unit, should have moved the camera to the maximum")

	cam.moveY(-305)
	assert.Equal(t, cam.Y(), WorldBounds.Min.Y, "Moving too many units back, should have moved the camera to the minimum")
}

func TestCameraZoom(t *testing.T) {
	cam := &cameraSystem{}
	cam.New()

	currentZ := cam.Z()

	cam.moveX(0.5)
	assert.Equal(t, cam.Z(), currentZ, "Moving in the X direction shouldn't change the zoom level")

	cam.moveX(-1)
	assert.Equal(t, cam.Z(), currentZ, "Moving in the X direction shouldn't change the zoom level")

	cam.moveY(0.5)
	assert.Equal(t, cam.Z(), currentZ, "Moving in the Y direction shouldn't change the zoom level")

	cam.moveY(-1)
	assert.Equal(t, cam.Z(), currentZ, "Moving in the Y direction shouldn't change the zoom level")

	cam.zoom(0.5)
	assert.Equal(t, cam.Z(), currentZ+0.5, "Should be zoomed in an additional 0.5")

	cam.zoom(-0.5)
	assert.Equal(t, cam.Z(), currentZ, "Should be zoomed out to the starting zoom level")

	cam.zoom(-1000)
	assert.Equal(t, cam.Z(), MinZoom, "Should be zoomed out to the minimum zoom level")

	cam.zoom(1000)
	assert.Equal(t, cam.Z(), MaxZoom, "Should be zoomed in to the maximum zoom level")
}

func TestCameraMoveToX(t *testing.T) {
	cam := &cameraSystem{}
	cam.New()
	WorldBounds = AABB{Point{0, 0}, Point{300, 300}}

	currentX := cam.X()

	cam.moveToX(currentX + 5)
	assert.Equal(t, cam.X(), currentX+5, "Moving to current + 5 should get us to current + 5")

	cam.moveToX(600)
	assert.Equal(t, cam.X(), WorldBounds.Max.X, "Moving to a location out of bounds, should get us to the maximum")

	cam.moveToX(-10)
	assert.Equal(t, cam.X(), WorldBounds.Min.X, "Moving to a location out of bounds, should get us to the minimum")
}

func TestCameraMoveToY(t *testing.T) {
	cam := &cameraSystem{}
	cam.New()
	WorldBounds = AABB{Point{0, 0}, Point{300, 300}}

	currentY := cam.Y()

	cam.moveToY(currentY + 5)
	assert.Equal(t, cam.Y(), currentY+5, "Moving to current + 5 should get us to current + 5")

	cam.moveToY(600)
	assert.Equal(t, cam.Y(), WorldBounds.Max.Y, "Moving to a location out of bounds, should get us to the maximum")

	cam.moveToY(-10)
	assert.Equal(t, cam.Y(), WorldBounds.Min.Y, "Moving to a location out of bounds, should get us to the minimum")
}

func TestCameraZoomTo(t *testing.T) {
	cam := &cameraSystem{}
	cam.New()

	currentZ := cam.Z()

	cam.zoomTo(currentZ + 1)
	assert.Equal(t, cam.Z(), currentZ+1, "Zooming to current + 1 should get us to current + 1")

	cam.zoomTo(600)
	assert.Equal(t, cam.Z(), MaxZoom, "Zooming too close, should get us to the minimum distance")

	cam.zoomTo(-10)
	assert.Equal(t, cam.Z(), MinZoom, "Zooming too far, should get us to the maximum distance")
}
<|endoftext|>


<commit_before>package ccd

import (
	"errors"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/jteeuwen/go-pkg-xmlx"
)

var (
	ResultsTid = []string{"2.16.840.1.113883.10.20.1.14", "2.16.840.1.113883.10.20.22.2.3.1"}

	ResultsParser = Parser{
		Type:     PARSE_SECTION,
		Values:   ResultsTid,
		Priority: 0,
		Func:     parseResults,
	}

	RANGE_SPLIT_RE = regexp.MustCompile(`\s*(;|,|\|)\s*`)
	RANGE_RE       = regexp.MustCompile(`(?P<text>[a-zA-Z\s]*?)\s*\(?(?P<low>[\d.]+)\s*[-–]\s*(?P<high>[\d.]+).*?\)?`)
	RANGE_MATH_RE  = regexp.MustCompile(`(?P<text>[a-zA-Z\s]*?)\s*\(?(?P<symbol>[<>=]+)\s*(?P<value>[\d.]+).*?\)?`)
)

type ResultValue struct {
	Type  string
	Value string
	Unit  string
}

//decodeResultValue decodes the <value> in an Observation Result
func decodeResultValue(n *xmlx.Node) ResultValue {
	//reference: http://www.cdapro.com/know/25047
	var rv ResultValue
	if n == nil {
		return rv
	}

	rv.Type = n.As("*", "type")
	switch rv.Type {

	case "PQ": //PhysicalQuantity(PQ) types contain a "unit" and a "value" attribute
		rv.Value = n.As("*", "value")
		rv.Unit = n.As("*", "unit")
	case "ST": //Character String (ST) types contain their value as the content of their node
		rv.Value = n.GetValue()

		//some EMRs use ST for data that should be a PQ, so we check for that.
		if strings.Count(rv.Value, " ") == 1 {
			parts := strings.Split(rv.Value, " ")
			value, unit := parts[0], parts[1]

			//values must be real numbers
			if _, err := strconv.ParseFloat(value, 64); err != nil {
				//probably a normal ST segment, don't do anything special.
				break
			}
			rv.Unit = unit
			rv.Value = value
			//TODO:  since we're essentially turning this ST into a PQ, should we change type to PQ?
			//as it is, if something is checking our result's Type and handling it specially, it wouldn't expect a ST result to have a .Unit
		}

		/*NYI: "ED"(Encapsulated Data) which is kind of a 'catch all' for any arbitrary data
		it can refer to elements anywhere in the document, and it could have any format, so we cant really support it
		*/
	case "CV", "CD": //Coded Value(CV) and ConceptDiscriptor(CD) are both similar.
		//this is a rather simplistic decoding, ignoring the codesystem and translations, but it works with our samples.
		//two of our sample ccdas use CV, but they both are nullflavor so we can't test them.
		//A lot more use "CD", when they aren't null our samples all use them for "positive" "negative" "normal" etc.
		rv.Value = n.As("*", "displayName")
	}

	return rv
}

type ResultRange struct {
	Gender       *string // M or F
	AgeLow       *float64
	AgeHigh      *float64
	Low          *float64
	High         *float64
	Text         *string
	OriginalText string
}

func (r ResultRange) IsZero() bool {
	return r.Gender == nil && r.AgeLow == nil &&
		r.AgeHigh == nil && r.Low == nil &&
		r.High == nil && r.Text == nil
}

type ResultRanges []ResultRange

func (r *ResultRanges) Parse(s string) {
	for _, part := range RANGE_SPLIT_RE.Split(s, -1) {
		if part == "NA" || part == "No data" {
			continue
		}

		rr := ResultRange{}

		rr.OriginalText = s

		if strings.HasPrefix(part, "M ") {
			gender := "M"
			rr.Gender = &gender
			part = part[2:]
		} else if strings.HasPrefix(part, "F ") {
			gender := "F"
			rr.Gender = &gender
			part = part[2:]
		}

		text := ""
		colonsplit := strings.Split(part, ":")
		if len(colonsplit) == 2 {
			text = colonsplit[0]
			part = colonsplit[1]
		}

		part = strings.Replace(part, "less than", "<", -1)
		part = strings.Replace(part, "below", "<", -1)
		part = strings.Replace(part, "greater than", ">", -1)
		part = strings.Replace(part, "above", ">", -1)
		part = strings.Replace(part, "equal to", "=", -1)

		err := parseRange(part, &text, &rr.Low, &rr.High)
		if err != nil {
			parseRangeMath(part, &text, &rr.Low, &rr.High)
		}

		// Handle when years are specified
		if strings.Contains(text, "years") {
			var empty string
			err := parseRange(text, &empty, &rr.AgeLow, &rr.AgeHigh)
			if err != nil {
				parseRangeMath(text, &empty, &rr.AgeLow, &rr.AgeHigh)
			}

			text = ""
		}

		if rr.IsZero() {
			part = strings.Trim(part, "()")
			if len(part) == 0 || strings.Contains(part, "/") {
				continue
			}
			text = part
		}

		if len(text) > 0 {
			rr.Text = &text
		}

		*r = append(*r, rr)
	}
}

// Find [numbers] - [numbers]
func parseRange(s string, text *string, low **float64, high **float64) error {
	data := RANGE_RE.FindStringSubmatch(s)
	if len(data) == 4 {
		if *text == "" {
			*text = data[1]
		}

		lowf, err := strconv.ParseFloat(data[2], 64)
		if err == nil {
			*low = &lowf
		}

		highf, err := strconv.ParseFloat(data[3], 64)
		if err == nil {
			*high = &highf
		}

		return nil
	}

	return errors.New("Not a range")
}

// Find <>=[numbers]. e.g. <5, >=6.5
func parseRangeMath(s string, text *string, low **float64, high **float64) error {
	data := RANGE_MATH_RE.FindStringSubmatch(s)
	if len(data) == 4 {
		if *text == "" {
			*text = data[1]
		}

		value, err := strconv.ParseFloat(data[3], 64)
		if err == nil {
			switch data[2] {
			case "<", "<=":
				*high = &value
			case ">", ">=":
				*low = &value
			case "=", "==":
				*low = &value
				*high = &value
			}
		}
	}

	return errors.New("Not a math range")
}

type ResultObservation struct {
	Date                time.Time
	Code                Code
	Value               ResultValue
	InterpretationCodes []string
	Ranges              []ResultRange
}

type Result struct {
	Date         time.Time
	Code         Code
	Observations []ResultObservation
}

func parseResults(node *xmlx.Node, ccd *CCD) []error {
	entryNodes := node.SelectNodes("*", "entry")
	for _, entryNode := range entryNodes {
		organizerNode := Nget(entryNode, "organizer")
		if organizerNode == nil {
			return nil
		}

		componentNodes := organizerNode.SelectNodes("*", "component")
		if componentNodes == nil {
			return nil
		}

		result := Result{}

		codeNode := Nget(organizerNode, "code")
		if codeNode != nil {
			result.Code.decode(codeNode)
		}

		if len(result.Code.DisplayName) == 0 {
			continue
		}

		effectiveTimeNode := Nget(organizerNode, "effectiveTime")
		t := decodeTime(effectiveTimeNode)
		result.Date = t.Value

		for _, componentNode := range componentNodes {
			obNode := Nget(componentNode, "observation")
			if obNode == nil {
				continue
			}

			observation := ResultObservation{}

			effectiveTimeNode := Nget(obNode, "effectiveTime")
			t = decodeTime(effectiveTimeNode)
			observation.Date = t.Value

			codeNode := Nget(obNode, "code")
			if codeNode != nil {
				observation.Code.decode(codeNode)
			}

			if len(observation.Code.DisplayName) == 0 {
				continue
			}

			observation.Value = decodeResultValue(Nget(obNode, "value"))

			icodeNodes := obNode.SelectNodes("*", "interpretationCode")
			if icodeNodes != nil {
				for _, icodeNode := range icodeNodes {
					observation.InterpretationCodes = append(observation.InterpretationCodes, icodeNode.As("*", "code"))
				}
			}

			obvRangeNode := Nget(obNode, "referenceRange", "observationRange")
			if obvRangeNode != nil {
				var resultRanges ResultRanges

				valueNode := Nget(obvRangeNode, "value")
				if valueNode != nil {
					lowNode := Nget(valueNode, "low")
					highNode := Nget(valueNode, "high")
					if lowNode == nil || highNode == nil {
						continue
					}
					lowf, _ := strconv.ParseFloat(lowNode.As("*", "value"), 64)
					highf, _ := strconv.ParseFloat(highNode.As("*", "value"), 64)

					resultRanges = append(resultRanges, ResultRange{
						Low:  &lowf,
						High: &highf,
					})
				} else {
					rangeText := obvRangeNode.S("*", "text")
					if len(rangeText) > 0 {
						resultRanges.Parse(rangeText)
					}
				}

				observation.Ranges = resultRanges
			}

			result.Observations = append(result.Observations, observation)
		}

		ccd.Results = append(ccd.Results, result)
	}

	return nil
}
<commit_msg>Don't remove observations in results if name is empty.<commit_after>package ccd

import (
	"errors"
	"regexp"
	"strconv"
	"strings"
	"time"

	"github.com/jteeuwen/go-pkg-xmlx"
)

var (
	ResultsTid = []string{"2.16.840.1.113883.10.20.1.14", "2.16.840.1.113883.10.20.22.2.3.1"}

	ResultsParser = Parser{
		Type:     PARSE_SECTION,
		Values:   ResultsTid,
		Priority: 0,
		Func:     parseResults,
	}

	RANGE_SPLIT_RE = regexp.MustCompile(`\s*(;|,|\|)\s*`)
	RANGE_RE       = regexp.MustCompile(`(?P<text>[a-zA-Z\s]*?)\s*\(?(?P<low>[\d.]+)\s*[-–]\s*(?P<high>[\d.]+).*?\)?`)
	RANGE_MATH_RE  = regexp.MustCompile(`(?P<text>[a-zA-Z\s]*?)\s*\(?(?P<symbol>[<>=]+)\s*(?P<value>[\d.]+).*?\)?`)
)

type ResultValue struct {
	Type  string
	Value string
	Unit  string
}

//decodeResultValue decodes the <value> in an Observation Result
func decodeResultValue(n *xmlx.Node) ResultValue {
	//reference: http://www.cdapro.com/know/25047
	var rv ResultValue
	if n == nil {
		return rv
	}

	rv.Type = n.As("*", "type")
	switch rv.Type {

	case "PQ": //PhysicalQuantity(PQ) types contain a "unit" and a "value" attribute
		rv.Value = n.As("*", "value")
		rv.Unit = n.As("*", "unit")
	case "ST": //Character String (ST) types contain their value as the content of their node
		rv.Value = n.GetValue()

		//some EMRs use ST for data that should be a PQ, so we check for that.
		if strings.Count(rv.Value, " ") == 1 {
			parts := strings.Split(rv.Value, " ")
			value, unit := parts[0], parts[1]

			//values must be real numbers
			if _, err := strconv.ParseFloat(value, 64); err != nil {
				//probably a normal ST segment, don't do anything special.
				break
			}
			rv.Unit = unit
			rv.Value = value
			//TODO:  since we're essentially turning this ST into a PQ, should we change type to PQ?
			//as it is, if something is checking our result's Type and handling it specially, it wouldn't expect a ST result to have a .Unit
		}

		/*NYI: "ED"(Encapsulated Data) which is kind of a 'catch all' for any arbitrary data
		it can refer to elements anywhere in the document, and it could have any format, so we cant really support it
		*/
	case "CV", "CD": //Coded Value(CV) and ConceptDiscriptor(CD) are both similar.
		//this is a rather simplistic decoding, ignoring the codesystem and translations, but it works with our samples.
		//two of our sample ccdas use CV, but they both are nullflavor so we can't test them.
		//A lot more use "CD", when they aren't null our samples all use them for "positive" "negative" "normal" etc.
		rv.Value = n.As("*", "displayName")
	}

	return rv
}

type ResultRange struct {
	Gender       *string // M or F
	AgeLow       *float64
	AgeHigh      *float64
	Low          *float64
	High         *float64
	Text         *string
	OriginalText string
}

func (r ResultRange) IsZero() bool {
	return r.Gender == nil && r.AgeLow == nil &&
		r.AgeHigh == nil && r.Low == nil &&
		r.High == nil && r.Text == nil
}

type ResultRanges []ResultRange

func (r *ResultRanges) Parse(s string) {
	for _, part := range RANGE_SPLIT_RE.Split(s, -1) {
		if part == "NA" || part == "No data" {
			continue
		}

		rr := ResultRange{}

		rr.OriginalText = s

		if strings.HasPrefix(part, "M ") {
			gender := "M"
			rr.Gender = &gender
			part = part[2:]
		} else if strings.HasPrefix(part, "F ") {
			gender := "F"
			rr.Gender = &gender
			part = part[2:]
		}

		text := ""
		colonsplit := strings.Split(part, ":")
		if len(colonsplit) == 2 {
			text = colonsplit[0]
			part = colonsplit[1]
		}

		part = strings.Replace(part, "less than", "<", -1)
		part = strings.Replace(part, "below", "<", -1)
		part = strings.Replace(part, "greater than", ">", -1)
		part = strings.Replace(part, "above", ">", -1)
		part = strings.Replace(part, "equal to", "=", -1)

		err := parseRange(part, &text, &rr.Low, &rr.High)
		if err != nil {
			parseRangeMath(part, &text, &rr.Low, &rr.High)
		}

		// Handle when years are specified
		if strings.Contains(text, "years") {
			var empty string
			err := parseRange(text, &empty, &rr.AgeLow, &rr.AgeHigh)
			if err != nil {
				parseRangeMath(text, &empty, &rr.AgeLow, &rr.AgeHigh)
			}

			text = ""
		}

		if rr.IsZero() {
			part = strings.Trim(part, "()")
			if len(part) == 0 || strings.Contains(part, "/") {
				continue
			}
			text = part
		}

		if len(text) > 0 {
			rr.Text = &text
		}

		*r = append(*r, rr)
	}
}

// Find [numbers] - [numbers]
func parseRange(s string, text *string, low **float64, high **float64) error {
	data := RANGE_RE.FindStringSubmatch(s)
	if len(data) == 4 {
		if *text == "" {
			*text = data[1]
		}

		lowf, err := strconv.ParseFloat(data[2], 64)
		if err == nil {
			*low = &lowf
		}

		highf, err := strconv.ParseFloat(data[3], 64)
		if err == nil {
			*high = &highf
		}

		return nil
	}

	return errors.New("Not a range")
}

// Find <>=[numbers]. e.g. <5, >=6.5
func parseRangeMath(s string, text *string, low **float64, high **float64) error {
	data := RANGE_MATH_RE.FindStringSubmatch(s)
	if len(data) == 4 {
		if *text == "" {
			*text = data[1]
		}

		value, err := strconv.ParseFloat(data[3], 64)
		if err == nil {
			switch data[2] {
			case "<", "<=":
				*high = &value
			case ">", ">=":
				*low = &value
			case "=", "==":
				*low = &value
				*high = &value
			}
		}
	}

	return errors.New("Not a math range")
}

type ResultObservation struct {
	Date                time.Time
	Code                Code
	Value               ResultValue
	InterpretationCodes []string
	Ranges              []ResultRange
}

type Result struct {
	Date         time.Time
	Code         Code
	Observations []ResultObservation
}

func parseResults(node *xmlx.Node, ccd *CCD) []error {
	entryNodes := node.SelectNodes("*", "entry")
	for _, entryNode := range entryNodes {
		organizerNode := Nget(entryNode, "organizer")
		if organizerNode == nil {
			return nil
		}

		componentNodes := organizerNode.SelectNodes("*", "component")
		if componentNodes == nil {
			return nil
		}

		result := Result{}

		codeNode := Nget(organizerNode, "code")
		if codeNode != nil {
			result.Code.decode(codeNode)
		}

		if len(result.Code.DisplayName) == 0 {
			continue
		}

		effectiveTimeNode := Nget(organizerNode, "effectiveTime")
		t := decodeTime(effectiveTimeNode)
		result.Date = t.Value

		for _, componentNode := range componentNodes {
			obNode := Nget(componentNode, "observation")
			if obNode == nil {
				continue
			}

			observation := ResultObservation{}

			effectiveTimeNode := Nget(obNode, "effectiveTime")
			t = decodeTime(effectiveTimeNode)
			observation.Date = t.Value

			codeNode := Nget(obNode, "code")
			if codeNode != nil {
				observation.Code.decode(codeNode)
			}

			observation.Value = decodeResultValue(Nget(obNode, "value"))

			icodeNodes := obNode.SelectNodes("*", "interpretationCode")
			if icodeNodes != nil {
				for _, icodeNode := range icodeNodes {
					observation.InterpretationCodes = append(observation.InterpretationCodes, icodeNode.As("*", "code"))
				}
			}

			obvRangeNode := Nget(obNode, "referenceRange", "observationRange")
			if obvRangeNode != nil {
				var resultRanges ResultRanges

				valueNode := Nget(obvRangeNode, "value")
				if valueNode != nil {
					lowNode := Nget(valueNode, "low")
					highNode := Nget(valueNode, "high")
					if lowNode == nil || highNode == nil {
						continue
					}
					lowf, _ := strconv.ParseFloat(lowNode.As("*", "value"), 64)
					highf, _ := strconv.ParseFloat(highNode.As("*", "value"), 64)

					resultRanges = append(resultRanges, ResultRange{
						Low:  &lowf,
						High: &highf,
					})
				} else {
					rangeText := obvRangeNode.S("*", "text")
					if len(rangeText) > 0 {
						resultRanges.Parse(rangeText)
					}
				}

				observation.Ranges = resultRanges
			}

			result.Observations = append(result.Observations, observation)
		}

		ccd.Results = append(ccd.Results, result)
	}

	return nil
}
<|endoftext|>