<commit_before>/*
 *  Copyright (c) 2011 NeuStar, 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.
 *
 *  NeuStar, the Neustar logo and related names and logos are registered
 *  trademarks, service marks or tradenames of NeuStar, Inc. All other
 *  product names, company names, marks, logos and symbols may be trademarks
 *  of their respective owners.
 */

package kafka

import (
	"testing"
	// "fmt"
	"bytes"
	"compress/gzip"
)

func TestMessageCreation(t *testing.T) {
	payload := []byte("testing")
	msg := NewMessage(payload)
	if msg.magic != 1 {
		t.Errorf("magic incorrect")
		t.Fail()
	}

	// generated by kafka-rb: e8 f3 5a 06
	expected := []byte{0xe8, 0xf3, 0x5a, 0x06}
	if !bytes.Equal(expected, msg.checksum[:]) {
		t.Fail()
	}
}

func TestMagic0MessageEncoding(t *testing.T) {
	// generated by kafka-rb:
	// test the old message format
	expected := []byte{0x00, 0x00, 0x00, 0x0c, 0x00, 0xe8, 0xf3, 0x5a, 0x06, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67}
	length, msgsDecoded, err := Decode(expected, DefaultCodecsMap)

	if length == 0 || msgsDecoded == nil || err != nil {
		t.Fail()
	}
	msgDecoded := msgsDecoded[0]

	payload := []byte("testing")
	if !bytes.Equal(payload, msgDecoded.payload) {
		t.Fatal("bytes not equal")
	}
	chksum := []byte{0xE8, 0xF3, 0x5A, 0x06}
	if !bytes.Equal(chksum, msgDecoded.checksum[:]) {
		t.Fatal("checksums do not match")
	}
	if msgDecoded.magic != 0 {
		t.Fatal("magic incorrect")
	}
}

func TestMessageEncoding(t *testing.T) {

	payload := []byte("testing")
	msg := NewMessage(payload)

	// generated by kafka-rb:
	expected := []byte{0x00, 0x00, 0x00, 0x0d, 0x01, 0x00, 0xe8, 0xf3, 0x5a, 0x06, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67}
	if !bytes.Equal(expected, msg.Encode()) {
		t.Fatalf("expected: % X\n but got: % X", expected, msg.Encode())
	}

	// verify round trip
	length, msgsDecoded, err := DecodeWithDefaultCodecs(msg.Encode())

	if length == 0 || msgsDecoded == nil || err != nil {
		t.Fatal("message is nil")
	}
	msgDecoded := msgsDecoded[0]

	if !bytes.Equal(msgDecoded.payload, payload) {
		t.Fatal("bytes not equal")
	}
	chksum := []byte{0xE8, 0xF3, 0x5A, 0x06}
	if !bytes.Equal(chksum, msgDecoded.checksum[:]) {
		t.Fatal("checksums do not match")
	}
	if msgDecoded.magic != 1 {
		t.Fatal("magic incorrect")
	}
}

func TestCompressedMessageEncodingCompare(t *testing.T) {
	payload := []byte("testing")
	uncompressedMsgBytes := NewMessage(payload).Encode()

	msgGzipBytes := NewMessageWithCodec(uncompressedMsgBytes, DefaultCodecsMap[GZIP_COMPRESSION_ID]).Encode()
	msgDefaultBytes := NewCompressedMessage(payload).Encode()
	if !bytes.Equal(msgDefaultBytes, msgGzipBytes) {
		t.Fatalf("uncompressed: % X \npayload: % X bytes not equal", msgDefaultBytes, msgGzipBytes)
	}
}

func TestCompressedMessageEncoding(t *testing.T) {
	payload := []byte("testing")
	uncompressedMsgBytes := NewMessage(payload).Encode()

	msg := NewMessageWithCodec(uncompressedMsgBytes, DefaultCodecsMap[GZIP_COMPRESSION_ID])

	expectedPayload := []byte{0x1F, 0x8B, 0x08, 0x00, 0x00, 0x09, 0x6E, 0x88, 0x04,
		0xFF, 0x62, 0x60, 0x60, 0xE0, 0x65, 0x64, 0x78, 0xF1, 0x39, 0x8A,
		0xAD, 0x24, 0xB5, 0xB8, 0x24, 0x33, 0x2F, 0x1D, 0x10, 0x00, 0x00,
		0xFF, 0xFF, 0x0C, 0x6A, 0x82, 0x91, 0x11, 0x00, 0x00, 0x00}

	expectedHeader := []byte{0x00, 0x00, 0x00, 0x2F, 0x01, 0x01, 0x96, 0x71, 0xA6, 0xE8}

	expected := make([]byte, len(expectedHeader)+len(expectedPayload))
	n := copy(expected, expectedHeader)
	copy(expected[n:], expectedPayload)

	if msg.compression != 1 {
		t.Fatalf("expected compression: 1 but got: %b", msg.compression)
	}

	zipper, _ := gzip.NewReader(bytes.NewBuffer(msg.payload))
	uncompressed := make([]byte, 100)
	n, _ = zipper.Read(uncompressed)
	uncompressed = uncompressed[:n]
	zipper.Close()

	if !bytes.Equal(uncompressed, uncompressedMsgBytes) {
		t.Fatalf("uncompressed: % X \npayload: % X bytes not equal", uncompressed, uncompressedMsgBytes)
	}

	if !bytes.Equal(expected, msg.Encode()) {
		t.Fatalf("expected: % X\n but got: % X", expected, msg.Encode())
	}

	// verify round trip
	length, msgsDecoded, err := Decode(msg.Encode(), DefaultCodecsMap)

	if length == 0 || msgsDecoded == nil || err != nil {
		t.Fatal("message is nil")
	}
	msgDecoded := msgsDecoded[0]

	if !bytes.Equal(msgDecoded.payload, payload) {
		t.Fatal("bytes not equal")
	}
	chksum := []byte{0xE8, 0xF3, 0x5A, 0x06}
	if !bytes.Equal(chksum, msgDecoded.checksum[:]) {
		t.Fatalf("checksums do not match, expected: % X but was: % X",
			chksum, msgDecoded.checksum[:])
	}
	if msgDecoded.magic != 1 {
		t.Fatal("magic incorrect")
	}
}

func TestLongCompressedMessageRoundTrip(t *testing.T) {
	payloadBuf := bytes.NewBuffer([]byte{})
	// make the test bigger than buffer allocated in the Decode
	for i := 0; i < 15; i++ {
		payloadBuf.Write([]byte("testing123 "))
	}

	uncompressedMsgBytes := NewMessage(payloadBuf.Bytes()).Encode()
	msg := NewMessageWithCodec(uncompressedMsgBytes, DefaultCodecsMap[GZIP_COMPRESSION_ID])

	zipper, _ := gzip.NewReader(bytes.NewBuffer(msg.payload))
	uncompressed := make([]byte, 200)
	n, _ := zipper.Read(uncompressed)
	uncompressed = uncompressed[:n]
	zipper.Close()

	if !bytes.Equal(uncompressed, uncompressedMsgBytes) {
		t.Fatalf("uncompressed: % X \npayload: % X bytes not equal",
			uncompressed, uncompressedMsgBytes)
	}

	// verify round trip
	length, msgsDecoded, err := Decode(msg.Encode(), DefaultCodecsMap)

	if length == 0 || msgsDecoded == nil || err != nil {
		t.Fatal("message is nil")
	}
	msgDecoded := msgsDecoded[0]

	if !bytes.Equal(msgDecoded.payload, payloadBuf.Bytes()) {
		t.Fatal("bytes not equal")
	}
	if msgDecoded.magic != 1 {
		t.Fatal("magic incorrect")
	}
}

func TestMultipleCompressedMessages(t *testing.T) {
	msgs := []*Message{NewMessage([]byte("testing")),
		NewMessage([]byte("multiple")),
		NewMessage([]byte("messages")),
	}
	msg := NewCompressedMessages(msgs...)

	length, msgsDecoded, err := DecodeWithDefaultCodecs(msg.Encode())
	if length == 0 || msgsDecoded == nil || err != nil {
		t.Fatal("msgsDecoded is nil")
	}

	// make sure the decompressed messages match what was put in
	for index, decodedMsg := range msgsDecoded {
		if !bytes.Equal(msgs[index].payload, decodedMsg.payload) {
			t.Fatalf("Payload doesn't match, expected: % X but was: % X\n",
				msgs[index].payload, decodedMsg.payload)
		}
	}
}

func TestRequestHeaderEncoding(t *testing.T) {
	broker := newBroker("localhost:9092", "test", 0)
	request := broker.EncodeRequestHeader(REQUEST_PRODUCE)

	// generated by kafka-rb:
	expected := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74,
		0x00, 0x00, 0x00, 0x00}

	if !bytes.Equal(expected, request.Bytes()) {
		t.Errorf("expected length: %d but got: %d", len(expected), len(request.Bytes()))
		t.Errorf("expected: %X\n but got: %X", expected, request)
		t.Fail()
	}
}

func TestPublishRequestEncoding(t *testing.T) {
	payload := []byte("testing")
	msg := NewMessage(payload)

	pubBroker := NewBrokerPublisher("localhost:9092", "test", 0)
	request := pubBroker.broker.EncodePublishRequest(msg)

	// generated by kafka-rb:
	expected := []byte{0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0d,
		/* magic  comp  ......  chksum ....     ..  payload .. */
		0x01, 0x00, 0xe8, 0xf3, 0x5a, 0x06, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67}

	if !bytes.Equal(expected, request) {
		t.Errorf("expected length: %d but got: %d", len(expected), len(request))
		t.Errorf("expected: % X\n but got: % X", expected, request)
		t.Fail()
	}
}

func TestConsumeRequestEncoding(t *testing.T) {

	pubBroker := NewBrokerPublisher("localhost:9092", "test", 0)
	request := pubBroker.broker.EncodeConsumeRequest(0, 1048576)

	// generated by kafka-rb, encode_request_size + encode_request
	expected := []byte{0x00, 0x00, 0x00, 0x18, 0x00, 0x01, 0x00, 0x04, 0x74,
		0x65, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00}

	if !bytes.Equal(expected, request) {
		t.Errorf("expected length: %d but got: %d", len(expected), len(request))
		t.Errorf("expected: % X\n but got: % X", expected, request)
		t.Fail()
	}
}

func TestCorruptPacket(t *testing.T) {
	total, msgs, err := DecodeWithDefaultCodecs([]byte{0x00, 0x00, 0x00, 0x18})
	if total != 0 {
		t.Errorf("total should be 0, but was: %d", total)
		t.Fail()
	}
	if len(msgs) != 0 {
		t.Errorf("msgs should be 0, but was: %d", len(msgs))
		t.Fail()
	}
	if nil == err {
		t.Error("was expecting a non-nil error")
		t.Fail()
	}
}
<commit_msg>added test for round-trip compression with Snappy<commit_after>/*
 *  Copyright (c) 2011 NeuStar, 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.
 *
 *  NeuStar, the Neustar logo and related names and logos are registered
 *  trademarks, service marks or tradenames of NeuStar, Inc. All other
 *  product names, company names, marks, logos and symbols may be trademarks
 *  of their respective owners.
 */

package kafka

import (
	"testing"
	// "fmt"
	"bytes"
	"compress/gzip"
)

func TestMessageCreation(t *testing.T) {
	payload := []byte("testing")
	msg := NewMessage(payload)
	if msg.magic != 1 {
		t.Errorf("magic incorrect")
		t.Fail()
	}

	// generated by kafka-rb: e8 f3 5a 06
	expected := []byte{0xe8, 0xf3, 0x5a, 0x06}
	if !bytes.Equal(expected, msg.checksum[:]) {
		t.Fail()
	}
}

func TestMagic0MessageEncoding(t *testing.T) {
	// generated by kafka-rb:
	// test the old message format
	expected := []byte{0x00, 0x00, 0x00, 0x0c, 0x00, 0xe8, 0xf3, 0x5a, 0x06, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67}
	length, msgsDecoded, err := Decode(expected, DefaultCodecsMap)

	if length == 0 || msgsDecoded == nil || err != nil {
		t.Fail()
	}
	msgDecoded := msgsDecoded[0]

	payload := []byte("testing")
	if !bytes.Equal(payload, msgDecoded.payload) {
		t.Fatal("bytes not equal")
	}
	chksum := []byte{0xE8, 0xF3, 0x5A, 0x06}
	if !bytes.Equal(chksum, msgDecoded.checksum[:]) {
		t.Fatal("checksums do not match")
	}
	if msgDecoded.magic != 0 {
		t.Fatal("magic incorrect")
	}
}

func TestMessageEncoding(t *testing.T) {

	payload := []byte("testing")
	msg := NewMessage(payload)

	// generated by kafka-rb:
	expected := []byte{0x00, 0x00, 0x00, 0x0d, 0x01, 0x00, 0xe8, 0xf3, 0x5a, 0x06, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67}
	if !bytes.Equal(expected, msg.Encode()) {
		t.Fatalf("expected: % X\n but got: % X", expected, msg.Encode())
	}

	// verify round trip
	length, msgsDecoded, err := DecodeWithDefaultCodecs(msg.Encode())

	if length == 0 || msgsDecoded == nil || err != nil {
		t.Fatal("message is nil")
	}
	msgDecoded := msgsDecoded[0]

	if !bytes.Equal(msgDecoded.payload, payload) {
		t.Fatal("bytes not equal")
	}
	chksum := []byte{0xE8, 0xF3, 0x5A, 0x06}
	if !bytes.Equal(chksum, msgDecoded.checksum[:]) {
		t.Fatal("checksums do not match")
	}
	if msgDecoded.magic != 1 {
		t.Fatal("magic incorrect")
	}
}

func TestCompressedMessageEncodingCompare(t *testing.T) {
	payload := []byte("testing")
	uncompressedMsgBytes := NewMessage(payload).Encode()

	msgGzipBytes := NewMessageWithCodec(uncompressedMsgBytes, DefaultCodecsMap[GZIP_COMPRESSION_ID]).Encode()
	msgDefaultBytes := NewCompressedMessage(payload).Encode()
	if !bytes.Equal(msgDefaultBytes, msgGzipBytes) {
		t.Fatalf("uncompressed: % X \npayload: % X bytes not equal", msgDefaultBytes, msgGzipBytes)
	}
}

func TestCompressedMessageEncoding(t *testing.T) {
	payload := []byte("testing")
	uncompressedMsgBytes := NewMessage(payload).Encode()

	msg := NewMessageWithCodec(uncompressedMsgBytes, DefaultCodecsMap[GZIP_COMPRESSION_ID])

	expectedPayload := []byte{0x1F, 0x8B, 0x08, 0x00, 0x00, 0x09, 0x6E, 0x88, 0x04,
		0xFF, 0x62, 0x60, 0x60, 0xE0, 0x65, 0x64, 0x78, 0xF1, 0x39, 0x8A,
		0xAD, 0x24, 0xB5, 0xB8, 0x24, 0x33, 0x2F, 0x1D, 0x10, 0x00, 0x00,
		0xFF, 0xFF, 0x0C, 0x6A, 0x82, 0x91, 0x11, 0x00, 0x00, 0x00}

	expectedHeader := []byte{0x00, 0x00, 0x00, 0x2F, 0x01, 0x01, 0x96, 0x71, 0xA6, 0xE8}

	expected := make([]byte, len(expectedHeader)+len(expectedPayload))
	n := copy(expected, expectedHeader)
	copy(expected[n:], expectedPayload)

	if msg.compression != 1 {
		t.Fatalf("expected compression: 1 but got: %b", msg.compression)
	}

	zipper, _ := gzip.NewReader(bytes.NewBuffer(msg.payload))
	uncompressed := make([]byte, 100)
	n, _ = zipper.Read(uncompressed)
	uncompressed = uncompressed[:n]
	zipper.Close()

	if !bytes.Equal(uncompressed, uncompressedMsgBytes) {
		t.Fatalf("uncompressed: % X \npayload: % X bytes not equal", uncompressed, uncompressedMsgBytes)
	}

	if !bytes.Equal(expected, msg.Encode()) {
		t.Fatalf("expected: % X\n but got: % X", expected, msg.Encode())
	}

	// verify round trip
	length, msgsDecoded, err := Decode(msg.Encode(), DefaultCodecsMap)

	if length == 0 || msgsDecoded == nil || err != nil {
		t.Fatal("message is nil")
	}
	msgDecoded := msgsDecoded[0]

	if !bytes.Equal(msgDecoded.payload, payload) {
		t.Fatal("bytes not equal")
	}
	chksum := []byte{0xE8, 0xF3, 0x5A, 0x06}
	if !bytes.Equal(chksum, msgDecoded.checksum[:]) {
		t.Fatalf("checksums do not match, expected: % X but was: % X",
			chksum, msgDecoded.checksum[:])
	}
	if msgDecoded.magic != 1 {
		t.Fatal("magic incorrect")
	}
}

func TestLongCompressedMessageRoundTrip(t *testing.T) {
	payloadBuf := bytes.NewBuffer([]byte{})
	// make the test bigger than buffer allocated in the Decode
	for i := 0; i < 15; i++ {
		payloadBuf.Write([]byte("testing123 "))
	}

	uncompressedMsgBytes := NewMessage(payloadBuf.Bytes()).Encode()
	msg := NewMessageWithCodec(uncompressedMsgBytes, DefaultCodecsMap[GZIP_COMPRESSION_ID])

	zipper, _ := gzip.NewReader(bytes.NewBuffer(msg.payload))
	uncompressed := make([]byte, 200)
	n, _ := zipper.Read(uncompressed)
	uncompressed = uncompressed[:n]
	zipper.Close()

	if !bytes.Equal(uncompressed, uncompressedMsgBytes) {
		t.Fatalf("uncompressed: % X \npayload: % X bytes not equal",
			uncompressed, uncompressedMsgBytes)
	}

	// verify round trip
	length, msgsDecoded, err := Decode(msg.Encode(), DefaultCodecsMap)

	if length == 0 || msgsDecoded == nil || err != nil {
		t.Fatal("message is nil")
	}
	msgDecoded := msgsDecoded[0]

	if !bytes.Equal(msgDecoded.payload, payloadBuf.Bytes()) {
		t.Fatal("bytes not equal")
	}
	if msgDecoded.magic != 1 {
		t.Fatal("magic incorrect")
	}
}

func TestLongCompressedMessageRoundTripSnappy(t *testing.T) {
	payloadBuf := bytes.NewBuffer([]byte{})
	// make the test bigger than buffer allocated in the Decode
	for i := 0; i < 15; i++ {
		payloadBuf.Write([]byte("testing123 "))
	}

	uncompressedMsgBytes := NewMessage(payloadBuf.Bytes()).Encode()
	msg := NewMessageWithCodec(uncompressedMsgBytes, DefaultCodecsMap[SNAPPY_COMPRESSION_ID])

	// verify round trip
	length, msgsDecoded, err := Decode(msg.Encode(), DefaultCodecsMap)

	if length == 0 || msgsDecoded == nil || err != nil {
		t.Fatal("message is nil")
	}
	msgDecoded := msgsDecoded[0]

	if !bytes.Equal(msgDecoded.payload, payloadBuf.Bytes()) {
		t.Fatal("bytes not equal")
	}
	if msgDecoded.magic != 1 {
		t.Fatal("magic incorrect")
	}
}

func TestMultipleCompressedMessages(t *testing.T) {
	msgs := []*Message{NewMessage([]byte("testing")),
		NewMessage([]byte("multiple")),
		NewMessage([]byte("messages")),
	}
	msg := NewCompressedMessages(msgs...)

	length, msgsDecoded, err := DecodeWithDefaultCodecs(msg.Encode())
	if length == 0 || msgsDecoded == nil || err != nil {
		t.Fatal("msgsDecoded is nil")
	}

	// make sure the decompressed messages match what was put in
	for index, decodedMsg := range msgsDecoded {
		if !bytes.Equal(msgs[index].payload, decodedMsg.payload) {
			t.Fatalf("Payload doesn't match, expected: % X but was: % X\n",
				msgs[index].payload, decodedMsg.payload)
		}
	}
}

func TestRequestHeaderEncoding(t *testing.T) {
	broker := newBroker("localhost:9092", "test", 0)
	request := broker.EncodeRequestHeader(REQUEST_PRODUCE)

	// generated by kafka-rb:
	expected := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74,
		0x00, 0x00, 0x00, 0x00}

	if !bytes.Equal(expected, request.Bytes()) {
		t.Errorf("expected length: %d but got: %d", len(expected), len(request.Bytes()))
		t.Errorf("expected: %X\n but got: %X", expected, request)
		t.Fail()
	}
}

func TestPublishRequestEncoding(t *testing.T) {
	payload := []byte("testing")
	msg := NewMessage(payload)

	pubBroker := NewBrokerPublisher("localhost:9092", "test", 0)
	request := pubBroker.broker.EncodePublishRequest(msg)

	// generated by kafka-rb:
	expected := []byte{0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x04, 0x74, 0x65, 0x73, 0x74,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0d,
		/* magic  comp  ......  chksum ....     ..  payload .. */
		0x01, 0x00, 0xe8, 0xf3, 0x5a, 0x06, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67}

	if !bytes.Equal(expected, request) {
		t.Errorf("expected length: %d but got: %d", len(expected), len(request))
		t.Errorf("expected: % X\n but got: % X", expected, request)
		t.Fail()
	}
}

func TestConsumeRequestEncoding(t *testing.T) {

	pubBroker := NewBrokerPublisher("localhost:9092", "test", 0)
	request := pubBroker.broker.EncodeConsumeRequest(0, 1048576)

	// generated by kafka-rb, encode_request_size + encode_request
	expected := []byte{0x00, 0x00, 0x00, 0x18, 0x00, 0x01, 0x00, 0x04, 0x74,
		0x65, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00}

	if !bytes.Equal(expected, request) {
		t.Errorf("expected length: %d but got: %d", len(expected), len(request))
		t.Errorf("expected: % X\n but got: % X", expected, request)
		t.Fail()
	}
}

func TestCorruptPacket(t *testing.T) {
	total, msgs, err := DecodeWithDefaultCodecs([]byte{0x00, 0x00, 0x00, 0x18})
	if total != 0 {
		t.Errorf("total should be 0, but was: %d", total)
		t.Fail()
	}
	if len(msgs) != 0 {
		t.Errorf("msgs should be 0, but was: %d", len(msgs))
		t.Fail()
	}
	if nil == err {
		t.Error("was expecting a non-nil error")
		t.Fail()
	}
}
<|endoftext|>


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

import (
	"fmt"
	"sort"
)

// A Change is a record of source code changes, recording user, language, and delta size.
type Change struct {
	user     string
	language string
	lines    int
}

type lessFunc func(p1, p2 *Change) bool

// multiSorter implements the Sort interface, sorting the changes within.
type multiSorter struct {
	changes []Change
	less    []lessFunc
}

// Sort sorts the argument slice according to the less functions passed to OrderedBy.
func (ms *multiSorter) Sort(changes []Change) {
	sort.Sort(ms)
}

// OrderedBy returns a Sorter that sorts using the less functions, in order.
// Call its Sort method to sort the data.
func OrderedBy(less ...lessFunc) *multiSorter {
	return &multiSorter{
		changes: changes,
		less:    less,
	}
}

// Len is part of sort.Interface.
func (ms *multiSorter) Len() int {
	return len(ms.changes)
}

// Swap is part of sort.Interface.
func (ms *multiSorter) Swap(i, j int) {
	ms.changes[i], ms.changes[j] = ms.changes[j], ms.changes[i]
}

// Less is part of sort.Interface. It is implemented by looping along the
// ordering functions until it finds a comparison that is either Less or
// !Less. Note that it can call the ordering functions twice per call. We
// could change the ordering functions to return -1, 0, 1 and reduce the
// number of calls for greater efficiency: an exercise for the reader.
func (ms *multiSorter) Less(i, j int) bool {
	p, q := &ms.changes[i], &ms.changes[j]
	// Try all but the last comparison.
	var k int
	for k = 0; k < len(ms.less)-1; k++ {
		less := ms.less[k]
		switch {
		case less(p, q):
			// p < q, so we have a decision.
			return true
		case less(q, p):
			// p > q, so we have a decision.
			return false
		}
		// p == q; try the next comparison.
	}
	// All comparisons to here said "equal", so just return whatever
	// the final comparison reports.
	return ms.less[k](p, q)
}

var changes = []Change{
	{"gri", "Go", 100},
	{"ken", "C", 150},
	{"glenda", "Go", 200},
	{"rsc", "Go", 200},
	{"r", "Go", 100},
	{"ken", "Go", 200},
	{"dmr", "C", 100},
	{"r", "C", 150},
	{"gri", "Smalltalk", 80},
}

// ExampleMultiKeys demonstrates a technique for sorting a struct type using different
// sets of multiple fields in the comparison. We chain together "Less" functions, each of
// which compares a single field.
func Example_sortMultiKeys() {
	// Closures that order the Change structure.
	user := func(c1, c2 *Change) bool {
		return c1.user < c2.user
	}
	language := func(c1, c2 *Change) bool {
		return c1.language < c2.language
	}
	increasingLines := func(c1, c2 *Change) bool {
		return c1.lines < c2.lines
	}
	decreasingLines := func(c1, c2 *Change) bool {
		return c1.lines > c2.lines // Note: > orders downwards.
	}

	// Simple use: Sort by user.
	OrderedBy(user).Sort(changes)
	fmt.Println("By user:", changes)

	// multiSorter implements the Sort interface, so we can also do this.
	sort.Sort(OrderedBy(user, increasingLines))
	fmt.Println("By user,<lines:", changes)

	// More examples.
	OrderedBy(user, decreasingLines).Sort(changes)
	fmt.Println("By user,>lines:", changes)

	OrderedBy(language, increasingLines).Sort(changes)
	fmt.Println("By language,<lines:", changes)

	OrderedBy(language, increasingLines, user).Sort(changes)
	fmt.Println("By language,<lines,user:", changes)

	// Output:
	//By user: [{dmr C 100} {glenda Go 200} {gri Smalltalk 80} {gri Go 100} {ken Go 200} {ken C 150} {r Go 100} {r C 150} {rsc Go 200}]
	//By user,<lines: [{dmr C 100} {glenda Go 200} {gri Smalltalk 80} {gri Go 100} {ken C 150} {ken Go 200} {r Go 100} {r C 150} {rsc Go 200}]
	//By user,>lines: [{dmr C 100} {glenda Go 200} {gri Go 100} {gri Smalltalk 80} {ken Go 200} {ken C 150} {r C 150} {r Go 100} {rsc Go 200}]
	//By language,<lines: [{dmr C 100} {ken C 150} {r C 150} {gri Go 100} {r Go 100} {ken Go 200} {glenda Go 200} {rsc Go 200} {gri Smalltalk 80}]
	//By language,<lines,user: [{dmr C 100} {ken C 150} {r C 150} {gri Go 100} {r Go 100} {glenda Go 200} {ken Go 200} {rsc Go 200} {gri Smalltalk 80}]

}
<commit_msg>sort: be consistent when describing "less: function in the multiKeys example s/ordering/less/g<commit_after>// Copyright 2013 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 sort_test

import (
	"fmt"
	"sort"
)

// A Change is a record of source code changes, recording user, language, and delta size.
type Change struct {
	user     string
	language string
	lines    int
}

type lessFunc func(p1, p2 *Change) bool

// multiSorter implements the Sort interface, sorting the changes within.
type multiSorter struct {
	changes []Change
	less    []lessFunc
}

// Sort sorts the argument slice according to the less functions passed to OrderedBy.
func (ms *multiSorter) Sort(changes []Change) {
	sort.Sort(ms)
}

// OrderedBy returns a Sorter that sorts using the less functions, in order.
// Call its Sort method to sort the data.
func OrderedBy(less ...lessFunc) *multiSorter {
	return &multiSorter{
		changes: changes,
		less:    less,
	}
}

// Len is part of sort.Interface.
func (ms *multiSorter) Len() int {
	return len(ms.changes)
}

// Swap is part of sort.Interface.
func (ms *multiSorter) Swap(i, j int) {
	ms.changes[i], ms.changes[j] = ms.changes[j], ms.changes[i]
}

// Less is part of sort.Interface. It is implemented by looping along the
// less functions until it finds a comparison that is either Less or
// !Less. Note that it can call the less functions twice per call. We
// could change the functions to return -1, 0, 1 and reduce the
// number of calls for greater efficiency: an exercise for the reader.
func (ms *multiSorter) Less(i, j int) bool {
	p, q := &ms.changes[i], &ms.changes[j]
	// Try all but the last comparison.
	var k int
	for k = 0; k < len(ms.less)-1; k++ {
		less := ms.less[k]
		switch {
		case less(p, q):
			// p < q, so we have a decision.
			return true
		case less(q, p):
			// p > q, so we have a decision.
			return false
		}
		// p == q; try the next comparison.
	}
	// All comparisons to here said "equal", so just return whatever
	// the final comparison reports.
	return ms.less[k](p, q)
}

var changes = []Change{
	{"gri", "Go", 100},
	{"ken", "C", 150},
	{"glenda", "Go", 200},
	{"rsc", "Go", 200},
	{"r", "Go", 100},
	{"ken", "Go", 200},
	{"dmr", "C", 100},
	{"r", "C", 150},
	{"gri", "Smalltalk", 80},
}

// ExampleMultiKeys demonstrates a technique for sorting a struct type using different
// sets of multiple fields in the comparison. We chain together "Less" functions, each of
// which compares a single field.
func Example_sortMultiKeys() {
	// Closures that order the Change structure.
	user := func(c1, c2 *Change) bool {
		return c1.user < c2.user
	}
	language := func(c1, c2 *Change) bool {
		return c1.language < c2.language
	}
	increasingLines := func(c1, c2 *Change) bool {
		return c1.lines < c2.lines
	}
	decreasingLines := func(c1, c2 *Change) bool {
		return c1.lines > c2.lines // Note: > orders downwards.
	}

	// Simple use: Sort by user.
	OrderedBy(user).Sort(changes)
	fmt.Println("By user:", changes)

	// multiSorter implements the Sort interface, so we can also do this.
	sort.Sort(OrderedBy(user, increasingLines))
	fmt.Println("By user,<lines:", changes)

	// More examples.
	OrderedBy(user, decreasingLines).Sort(changes)
	fmt.Println("By user,>lines:", changes)

	OrderedBy(language, increasingLines).Sort(changes)
	fmt.Println("By language,<lines:", changes)

	OrderedBy(language, increasingLines, user).Sort(changes)
	fmt.Println("By language,<lines,user:", changes)

	// Output:
	//By user: [{dmr C 100} {glenda Go 200} {gri Smalltalk 80} {gri Go 100} {ken Go 200} {ken C 150} {r Go 100} {r C 150} {rsc Go 200}]
	//By user,<lines: [{dmr C 100} {glenda Go 200} {gri Smalltalk 80} {gri Go 100} {ken C 150} {ken Go 200} {r Go 100} {r C 150} {rsc Go 200}]
	//By user,>lines: [{dmr C 100} {glenda Go 200} {gri Go 100} {gri Smalltalk 80} {ken Go 200} {ken C 150} {r C 150} {r Go 100} {rsc Go 200}]
	//By language,<lines: [{dmr C 100} {ken C 150} {r C 150} {gri Go 100} {r Go 100} {ken Go 200} {glenda Go 200} {rsc Go 200} {gri Smalltalk 80}]
	//By language,<lines,user: [{dmr C 100} {ken C 150} {r C 150} {gri Go 100} {r Go 100} {glenda Go 200} {ken Go 200} {rsc Go 200} {gri Smalltalk 80}]

}
<|endoftext|>


<commit_before>package prelude

const jsmapping = `
var $jsObjectPtr, $jsErrorPtr;

var $needsExternalization = function(t) {
  switch (t.kind) {
    case $kindBool:
    case $kindInt:
    case $kindInt8:
    case $kindInt16:
    case $kindInt32:
    case $kindUint:
    case $kindUint8:
    case $kindUint16:
    case $kindUint32:
    case $kindUintptr:
    case $kindFloat32:
    case $kindFloat64:
      return false;
    default:
      return t !== $jsObjectPtr;
  }
};

var $externalize = function(v, t) {
  if (t === $jsObjectPtr) {
    return v;
  }
  switch (t.kind) {
  case $kindBool:
  case $kindInt:
  case $kindInt8:
  case $kindInt16:
  case $kindInt32:
  case $kindUint:
  case $kindUint8:
  case $kindUint16:
  case $kindUint32:
  case $kindUintptr:
  case $kindFloat32:
  case $kindFloat64:
    return v;
  case $kindInt64:
  case $kindUint64:
    return $flatten64(v);
  case $kindArray:
    if ($needsExternalization(t.elem)) {
      return $mapArray(v, function(e) { return $externalize(e, t.elem); });
    }
    return v;
  case $kindFunc:
    return $externalizeFunction(v, t, false);
  case $kindInterface:
    if (v === $ifaceNil) {
      return null;
    }
    if (v.constructor === $jsObjectPtr) {
      return v.$val.object;
    }
    return $externalize(v.$val, v.constructor);
  case $kindMap:
    var m = {};
    var keys = $keys(v);
    for (var i = 0; i < keys.length; i++) {
      var entry = v[keys[i]];
      m[$externalize(entry.k, t.key)] = $externalize(entry.v, t.elem);
    }
    return m;
  case $kindPtr:
    if (v === t.nil) {
      return null;
    }
    return $externalize(v.$get(), t.elem);
  case $kindSlice:
    if ($needsExternalization(t.elem)) {
      return $mapArray($sliceToArray(v), function(e) { return $externalize(e, t.elem); });
    }
    return $sliceToArray(v);
  case $kindString:
    if ($isASCII(v)) {
      return v;
    }
    var s = "", r;
    for (var i = 0; i < v.length; i += r[1]) {
      r = $decodeRune(v, i);
      var c = r[0];
      if (c > 0xFFFF) {
        var h = Math.floor((c - 0x10000) / 0x400) + 0xD800;
        var l = (c - 0x10000) % 0x400 + 0xDC00;
        s += String.fromCharCode(h, l);
        continue;
      }
      s += String.fromCharCode(c);
    }
    return s;
  case $kindStruct:
    var timePkg = $packages["time"];
    if (timePkg !== undefined && v.constructor === timePkg.Time.ptr) {
      var milli = $div64(v.UnixNano(), new $Int64(0, 1000000));
      return new Date($flatten64(milli));
    }

    var noJsObject = {};
    var searchJsObject = function(v, t) {
      if (t === $jsObjectPtr) {
        return v;
      }
      switch (t.kind) {
      case $kindPtr:
        if (v === t.nil) {
          return noJsObject;
        }
        return searchJsObject(v.$get(), t.elem);
      case $kindStruct:
        var f = t.fields[0];
        return searchJsObject(v[f.prop], f.typ);
      case $kindInterface:
        return searchJsObject(v.$val, v.constructor);
      default:
        return noJsObject;
      }
    };
    var o = searchJsObject(v, t);
    if (o !== noJsObject) {
      return o;
    }

    o = {};
    for (var i = 0; i < t.fields.length; i++) {
      var f = t.fields[i];
      if (!f.exported) {
        continue;
      }
      o[f.name] = $externalize(v[f.prop], f.typ);
    }
    return o;
  }
  $throwRuntimeError("cannot externalize " + t.string);
};

var $externalizeFunction = function(v, t, passThis) {
  if (v === $throwNilPointerError) {
    return null;
  }
  if (v.$externalizeWrapper === undefined) {
    $checkForDeadlock = false;
    v.$externalizeWrapper = function() {
      var args = [];
      for (var i = 0; i < t.params.length; i++) {
        if (t.variadic && i === t.params.length - 1) {
          var vt = t.params[i].elem, varargs = [];
          for (var j = i; j < arguments.length; j++) {
            varargs.push($internalize(arguments[j], vt));
          }
          args.push(new (t.params[i])(varargs));
          break;
        }
        args.push($internalize(arguments[i], t.params[i]));
      }
      var canBlock = $curGoroutine.canBlock;
      $curGoroutine.canBlock = false;
      try {
        var result = v.apply(passThis ? this : undefined, args);
      } finally {
        $curGoroutine.canBlock = canBlock;
      }
      switch (t.results.length) {
      case 0:
        return;
      case 1:
        return $externalize(result, t.results[0]);
      default:
        for (var i = 0; i < t.results.length; i++) {
          result[i] = $externalize(result[i], t.results[i]);
        }
        return result;
      }
    };
  }
  return v.$externalizeWrapper;
};

var $internalize = function(v, t, recv) {
  if (t === $jsObjectPtr) {
    return v;
  }
  if (t === $jsObjectPtr.elem) {
    $throwRuntimeError("cannot internalize js.Object, use *js.Object instead");
  }
  if (v && v.__internal_object__ !== undefined) {
    return $assertType(v.__internal_object__, t, false);
  }
  var timePkg = $packages["time"];
  if (timePkg !== undefined && t === timePkg.Time) {
    if (!(v !== null && v !== undefined && v.constructor === Date)) {
      $throwRuntimeError("cannot internalize time.Time from " + typeof v + ", must be Date");
    }
    return timePkg.Unix(new $Int64(0, 0), new $Int64(0, v.getTime() * 1000000));
  }
  switch (t.kind) {
  case $kindBool:
    return !!v;
  case $kindInt:
    return parseInt(v);
  case $kindInt8:
    return parseInt(v) << 24 >> 24;
  case $kindInt16:
    return parseInt(v) << 16 >> 16;
  case $kindInt32:
    return parseInt(v) >> 0;
  case $kindUint:
    return parseInt(v);
  case $kindUint8:
    return parseInt(v) << 24 >>> 24;
  case $kindUint16:
    return parseInt(v) << 16 >>> 16;
  case $kindUint32:
  case $kindUintptr:
    return parseInt(v) >>> 0;
  case $kindInt64:
  case $kindUint64:
    return new t(0, v);
  case $kindFloat32:
  case $kindFloat64:
    return parseFloat(v);
  case $kindArray:
    if (v.length !== t.len) {
      $throwRuntimeError("got array with wrong size from JavaScript native");
    }
    return $mapArray(v, function(e) { return $internalize(e, t.elem); });
  case $kindFunc:
    return function() {
      var args = [];
      for (var i = 0; i < t.params.length; i++) {
        if (t.variadic && i === t.params.length - 1) {
          var vt = t.params[i].elem, varargs = arguments[i];
          for (var j = 0; j < varargs.$length; j++) {
            args.push($externalize(varargs.$array[varargs.$offset + j], vt));
          }
          break;
        }
        args.push($externalize(arguments[i], t.params[i]));
      }
      var result = v.apply(recv, args);
      switch (t.results.length) {
      case 0:
        return;
      case 1:
        return $internalize(result, t.results[0]);
      default:
        for (var i = 0; i < t.results.length; i++) {
          result[i] = $internalize(result[i], t.results[i]);
        }
        return result;
      }
    };
  case $kindInterface:
    if (t.methods.length !== 0) {
      $throwRuntimeError("cannot internalize " + t.string);
    }
    if (v === null) {
      return $ifaceNil;
    }
    if (v === undefined) {
      return new $jsObjectPtr(undefined);
    }
    switch (v.constructor) {
    case Int8Array:
      return new ($sliceType($Int8))(v);
    case Int16Array:
      return new ($sliceType($Int16))(v);
    case Int32Array:
      return new ($sliceType($Int))(v);
    case Uint8Array:
      return new ($sliceType($Uint8))(v);
    case Uint16Array:
      return new ($sliceType($Uint16))(v);
    case Uint32Array:
      return new ($sliceType($Uint))(v);
    case Float32Array:
      return new ($sliceType($Float32))(v);
    case Float64Array:
      return new ($sliceType($Float64))(v);
    case Array:
      return $internalize(v, $sliceType($emptyInterface));
    case Boolean:
      return new $Bool(!!v);
    case Date:
      if (timePkg === undefined) {
        /* time package is not present, internalize as &js.Object{Date} so it can be externalized into original Date. */
        return new $jsObjectPtr(v);
      }
      return new timePkg.Time($internalize(v, timePkg.Time));
    case Function:
      var funcType = $funcType([$sliceType($emptyInterface)], [$jsObjectPtr], true);
      return new funcType($internalize(v, funcType));
    case Number:
      return new $Float64(parseFloat(v));
    case String:
      return new $String($internalize(v, $String));
    default:
      if ($global.Node && v instanceof $global.Node) {
        return new $jsObjectPtr(v);
      }
      var mapType = $mapType($String, $emptyInterface);
      return new mapType($internalize(v, mapType));
    }
  case $kindMap:
    var m = {};
    var keys = $keys(v);
    for (var i = 0; i < keys.length; i++) {
      var k = $internalize(keys[i], t.key);
      m[t.key.keyFor(k)] = { k: k, v: $internalize(v[keys[i]], t.elem) };
    }
    return m;
  case $kindPtr:
    if (t.elem.kind === $kindStruct) {
      return $internalize(v, t.elem);
    }
  case $kindSlice:
    return new t($mapArray(v, function(e) { return $internalize(e, t.elem); }));
  case $kindString:
    v = String(v);
    if ($isASCII(v)) {
      return v;
    }
    var s = "";
    var i = 0;
    while (i < v.length) {
      var h = v.charCodeAt(i);
      if (0xD800 <= h && h <= 0xDBFF) {
        var l = v.charCodeAt(i + 1);
        var c = (h - 0xD800) * 0x400 + l - 0xDC00 + 0x10000;
        s += $encodeRune(c);
        i += 2;
        continue;
      }
      s += $encodeRune(h);
      i++;
    }
    return s;
  case $kindStruct:
    var noJsObject = {};
    var searchJsObject = function(t) {
      if (t === $jsObjectPtr) {
        return v;
      }
      if (t === $jsObjectPtr.elem) {
        $throwRuntimeError("cannot internalize js.Object, use *js.Object instead");
      }
      switch (t.kind) {
      case $kindPtr:
        return searchJsObject(t.elem);
      case $kindStruct:
        var f = t.fields[0];
        var o = searchJsObject(f.typ);
        if (o !== noJsObject) {
          var n = new t.ptr();
          n[f.prop] = o;
          return n;
        }
        return noJsObject;
      default:
        return noJsObject;
      }
    };
    var o = searchJsObject(t);
    if (o !== noJsObject) {
      return o;
    }
  }
  $throwRuntimeError("cannot internalize " + t.string);
};

/* $isASCII reports whether string s contains only ASCII characters. */
var $isASCII = function(s) {
  for (var i = 0; i < s.length; i++) {
    if (s.charCodeAt(i) >= 128) {
      return false;
    }
  }
  return true;
};
`
<commit_msg>compiler/prelude: Remove remaining unused canBlock. (#706)<commit_after>package prelude

const jsmapping = `
var $jsObjectPtr, $jsErrorPtr;

var $needsExternalization = function(t) {
  switch (t.kind) {
    case $kindBool:
    case $kindInt:
    case $kindInt8:
    case $kindInt16:
    case $kindInt32:
    case $kindUint:
    case $kindUint8:
    case $kindUint16:
    case $kindUint32:
    case $kindUintptr:
    case $kindFloat32:
    case $kindFloat64:
      return false;
    default:
      return t !== $jsObjectPtr;
  }
};

var $externalize = function(v, t) {
  if (t === $jsObjectPtr) {
    return v;
  }
  switch (t.kind) {
  case $kindBool:
  case $kindInt:
  case $kindInt8:
  case $kindInt16:
  case $kindInt32:
  case $kindUint:
  case $kindUint8:
  case $kindUint16:
  case $kindUint32:
  case $kindUintptr:
  case $kindFloat32:
  case $kindFloat64:
    return v;
  case $kindInt64:
  case $kindUint64:
    return $flatten64(v);
  case $kindArray:
    if ($needsExternalization(t.elem)) {
      return $mapArray(v, function(e) { return $externalize(e, t.elem); });
    }
    return v;
  case $kindFunc:
    return $externalizeFunction(v, t, false);
  case $kindInterface:
    if (v === $ifaceNil) {
      return null;
    }
    if (v.constructor === $jsObjectPtr) {
      return v.$val.object;
    }
    return $externalize(v.$val, v.constructor);
  case $kindMap:
    var m = {};
    var keys = $keys(v);
    for (var i = 0; i < keys.length; i++) {
      var entry = v[keys[i]];
      m[$externalize(entry.k, t.key)] = $externalize(entry.v, t.elem);
    }
    return m;
  case $kindPtr:
    if (v === t.nil) {
      return null;
    }
    return $externalize(v.$get(), t.elem);
  case $kindSlice:
    if ($needsExternalization(t.elem)) {
      return $mapArray($sliceToArray(v), function(e) { return $externalize(e, t.elem); });
    }
    return $sliceToArray(v);
  case $kindString:
    if ($isASCII(v)) {
      return v;
    }
    var s = "", r;
    for (var i = 0; i < v.length; i += r[1]) {
      r = $decodeRune(v, i);
      var c = r[0];
      if (c > 0xFFFF) {
        var h = Math.floor((c - 0x10000) / 0x400) + 0xD800;
        var l = (c - 0x10000) % 0x400 + 0xDC00;
        s += String.fromCharCode(h, l);
        continue;
      }
      s += String.fromCharCode(c);
    }
    return s;
  case $kindStruct:
    var timePkg = $packages["time"];
    if (timePkg !== undefined && v.constructor === timePkg.Time.ptr) {
      var milli = $div64(v.UnixNano(), new $Int64(0, 1000000));
      return new Date($flatten64(milli));
    }

    var noJsObject = {};
    var searchJsObject = function(v, t) {
      if (t === $jsObjectPtr) {
        return v;
      }
      switch (t.kind) {
      case $kindPtr:
        if (v === t.nil) {
          return noJsObject;
        }
        return searchJsObject(v.$get(), t.elem);
      case $kindStruct:
        var f = t.fields[0];
        return searchJsObject(v[f.prop], f.typ);
      case $kindInterface:
        return searchJsObject(v.$val, v.constructor);
      default:
        return noJsObject;
      }
    };
    var o = searchJsObject(v, t);
    if (o !== noJsObject) {
      return o;
    }

    o = {};
    for (var i = 0; i < t.fields.length; i++) {
      var f = t.fields[i];
      if (!f.exported) {
        continue;
      }
      o[f.name] = $externalize(v[f.prop], f.typ);
    }
    return o;
  }
  $throwRuntimeError("cannot externalize " + t.string);
};

var $externalizeFunction = function(v, t, passThis) {
  if (v === $throwNilPointerError) {
    return null;
  }
  if (v.$externalizeWrapper === undefined) {
    $checkForDeadlock = false;
    v.$externalizeWrapper = function() {
      var args = [];
      for (var i = 0; i < t.params.length; i++) {
        if (t.variadic && i === t.params.length - 1) {
          var vt = t.params[i].elem, varargs = [];
          for (var j = i; j < arguments.length; j++) {
            varargs.push($internalize(arguments[j], vt));
          }
          args.push(new (t.params[i])(varargs));
          break;
        }
        args.push($internalize(arguments[i], t.params[i]));
      }
      var result = v.apply(passThis ? this : undefined, args);
      switch (t.results.length) {
      case 0:
        return;
      case 1:
        return $externalize(result, t.results[0]);
      default:
        for (var i = 0; i < t.results.length; i++) {
          result[i] = $externalize(result[i], t.results[i]);
        }
        return result;
      }
    };
  }
  return v.$externalizeWrapper;
};

var $internalize = function(v, t, recv) {
  if (t === $jsObjectPtr) {
    return v;
  }
  if (t === $jsObjectPtr.elem) {
    $throwRuntimeError("cannot internalize js.Object, use *js.Object instead");
  }
  if (v && v.__internal_object__ !== undefined) {
    return $assertType(v.__internal_object__, t, false);
  }
  var timePkg = $packages["time"];
  if (timePkg !== undefined && t === timePkg.Time) {
    if (!(v !== null && v !== undefined && v.constructor === Date)) {
      $throwRuntimeError("cannot internalize time.Time from " + typeof v + ", must be Date");
    }
    return timePkg.Unix(new $Int64(0, 0), new $Int64(0, v.getTime() * 1000000));
  }
  switch (t.kind) {
  case $kindBool:
    return !!v;
  case $kindInt:
    return parseInt(v);
  case $kindInt8:
    return parseInt(v) << 24 >> 24;
  case $kindInt16:
    return parseInt(v) << 16 >> 16;
  case $kindInt32:
    return parseInt(v) >> 0;
  case $kindUint:
    return parseInt(v);
  case $kindUint8:
    return parseInt(v) << 24 >>> 24;
  case $kindUint16:
    return parseInt(v) << 16 >>> 16;
  case $kindUint32:
  case $kindUintptr:
    return parseInt(v) >>> 0;
  case $kindInt64:
  case $kindUint64:
    return new t(0, v);
  case $kindFloat32:
  case $kindFloat64:
    return parseFloat(v);
  case $kindArray:
    if (v.length !== t.len) {
      $throwRuntimeError("got array with wrong size from JavaScript native");
    }
    return $mapArray(v, function(e) { return $internalize(e, t.elem); });
  case $kindFunc:
    return function() {
      var args = [];
      for (var i = 0; i < t.params.length; i++) {
        if (t.variadic && i === t.params.length - 1) {
          var vt = t.params[i].elem, varargs = arguments[i];
          for (var j = 0; j < varargs.$length; j++) {
            args.push($externalize(varargs.$array[varargs.$offset + j], vt));
          }
          break;
        }
        args.push($externalize(arguments[i], t.params[i]));
      }
      var result = v.apply(recv, args);
      switch (t.results.length) {
      case 0:
        return;
      case 1:
        return $internalize(result, t.results[0]);
      default:
        for (var i = 0; i < t.results.length; i++) {
          result[i] = $internalize(result[i], t.results[i]);
        }
        return result;
      }
    };
  case $kindInterface:
    if (t.methods.length !== 0) {
      $throwRuntimeError("cannot internalize " + t.string);
    }
    if (v === null) {
      return $ifaceNil;
    }
    if (v === undefined) {
      return new $jsObjectPtr(undefined);
    }
    switch (v.constructor) {
    case Int8Array:
      return new ($sliceType($Int8))(v);
    case Int16Array:
      return new ($sliceType($Int16))(v);
    case Int32Array:
      return new ($sliceType($Int))(v);
    case Uint8Array:
      return new ($sliceType($Uint8))(v);
    case Uint16Array:
      return new ($sliceType($Uint16))(v);
    case Uint32Array:
      return new ($sliceType($Uint))(v);
    case Float32Array:
      return new ($sliceType($Float32))(v);
    case Float64Array:
      return new ($sliceType($Float64))(v);
    case Array:
      return $internalize(v, $sliceType($emptyInterface));
    case Boolean:
      return new $Bool(!!v);
    case Date:
      if (timePkg === undefined) {
        /* time package is not present, internalize as &js.Object{Date} so it can be externalized into original Date. */
        return new $jsObjectPtr(v);
      }
      return new timePkg.Time($internalize(v, timePkg.Time));
    case Function:
      var funcType = $funcType([$sliceType($emptyInterface)], [$jsObjectPtr], true);
      return new funcType($internalize(v, funcType));
    case Number:
      return new $Float64(parseFloat(v));
    case String:
      return new $String($internalize(v, $String));
    default:
      if ($global.Node && v instanceof $global.Node) {
        return new $jsObjectPtr(v);
      }
      var mapType = $mapType($String, $emptyInterface);
      return new mapType($internalize(v, mapType));
    }
  case $kindMap:
    var m = {};
    var keys = $keys(v);
    for (var i = 0; i < keys.length; i++) {
      var k = $internalize(keys[i], t.key);
      m[t.key.keyFor(k)] = { k: k, v: $internalize(v[keys[i]], t.elem) };
    }
    return m;
  case $kindPtr:
    if (t.elem.kind === $kindStruct) {
      return $internalize(v, t.elem);
    }
  case $kindSlice:
    return new t($mapArray(v, function(e) { return $internalize(e, t.elem); }));
  case $kindString:
    v = String(v);
    if ($isASCII(v)) {
      return v;
    }
    var s = "";
    var i = 0;
    while (i < v.length) {
      var h = v.charCodeAt(i);
      if (0xD800 <= h && h <= 0xDBFF) {
        var l = v.charCodeAt(i + 1);
        var c = (h - 0xD800) * 0x400 + l - 0xDC00 + 0x10000;
        s += $encodeRune(c);
        i += 2;
        continue;
      }
      s += $encodeRune(h);
      i++;
    }
    return s;
  case $kindStruct:
    var noJsObject = {};
    var searchJsObject = function(t) {
      if (t === $jsObjectPtr) {
        return v;
      }
      if (t === $jsObjectPtr.elem) {
        $throwRuntimeError("cannot internalize js.Object, use *js.Object instead");
      }
      switch (t.kind) {
      case $kindPtr:
        return searchJsObject(t.elem);
      case $kindStruct:
        var f = t.fields[0];
        var o = searchJsObject(f.typ);
        if (o !== noJsObject) {
          var n = new t.ptr();
          n[f.prop] = o;
          return n;
        }
        return noJsObject;
      default:
        return noJsObject;
      }
    };
    var o = searchJsObject(t);
    if (o !== noJsObject) {
      return o;
    }
  }
  $throwRuntimeError("cannot internalize " + t.string);
};

/* $isASCII reports whether string s contains only ASCII characters. */
var $isASCII = function(s) {
  for (var i = 0; i < s.length; i++) {
    if (s.charCodeAt(i) >= 128) {
      return false;
    }
  }
  return true;
};
`
<|endoftext|>


<commit_before>// Package js provides functions for interacting with native JavaScript APIs. Calls to these functions are treated specially by GopherJS and translated directly to their JavaScript syntax.
//
// Type conversions between Go types and JavaScript types are performed automatically according to the following table:
//
//  | Go types                       | Go interface type              | JavaScript type |
//  | ------------------------------ | ------------------------------ | --------------- |
//  | bool                           | bool                           | Boolean         |
//  | int?, uint?, float?            | float64                        | Number          |
//  | string                         | string                         | String          |
//  | [?]int8                        | []int8                         | Int8Array       |
//  | [?]int16                       | []int16                        | Int16Array      |
//  | [?]int32, [?]int               | []int                          | Int32Array      |
//  | [?]uint8                       | []uint8                        | Int8Array       |
//  | [?]uint16                      | []uint16                       | Int16Array      |
//  | [?]uint32, [?]uint, [?]uintptr | []uint                         | Int32Array      |
//  | [?]float32                     | []float32                      | Float32Array    |
//  | [?]float64                     | []float64                      | Float64Array    |
//  | all other slices and arrays    | []interface{}                  | Array           |
//  | maps, structs                  | map[string]interface{}         | Object          |
//  | functions                      | func(...interface{}) js.Object | Function        |
//  | time.Time                      | time.Time                      | Date            |
//
// The second column denotes the types that are used when converting to `interface{}`. Additionally, a pointer to a named type is passed to JavaScript as an object which has wrappers for the type's exported methods. This can be used to provide getter and setter methods for Go fields to JavaScript.
package js

// Object is a container for a native JavaScript object. Calls to its methods are treated specially by GopherJS and translated directly to their JavaScript syntax.
type Object interface {

	// Get returns the object's property with the given name.
	Get(name string) Object

	// Set assigns the value to the object's property with the given name.
	Set(name string, value interface{})

	// Delete removes the object's property with the given name.
	Delete(name string)

	// Get returns the object's "length" property, converted to int.
	Length() int

	// Index returns the i'th element of an array.
	Index(i int) Object

	// SetIndex sets the i'th element of an array.
	SetIndex(i int, value interface{})

	// Call calls the object's method with the given name.
	Call(name string, args ...interface{}) Object

	// Invoce calls the object itself. This will fail if it is not a function.
	Invoke(args ...interface{}) Object

	// New creates a new instance of this type object. This will fail if it not a function (constructor).
	New(args ...interface{}) Object

	// Bool returns the object converted to bool according to JavaScript type conversions.
	Bool() bool

	// Str returns the object converted to string according to JavaScript type conversions. Does not implement fmt.Stringer on purpose.
	Str() string

	// Int returns the object converted to int according to JavaScript type conversions (parseInt).
	Int() int

	// Int64 returns the object converted to int64 according to JavaScript type conversions (parseInt).
	Int64() int64

	// Uint64 returns the object converted to uint64 according to JavaScript type conversions (parseInt).
	Uint64() uint64

	// Float returns the object converted to float64 according to JavaScript type conversions (parseFloat).
	Float() float64

	// Interface returns the object converted to interface{}. See GopherJS' README for details.
	Interface() interface{}

	// Unsafe returns the object as an uintptr, which can be converted via unsafe.Pointer. Not intended for public use.
	Unsafe() uintptr

	// IsUndefined returns true if the object is the JavaScript value "undefine".
	IsUndefined() bool

	// IsNull returns true if the object is the JavaScript value "null".
	IsNull() bool
}

// Error encapsulates JavaScript errors. Those are turned into a Go panic and may be rescued, giving an *Error that holds the JavaScript error object.
type Error struct {
	Object
}

// Error returns the message of the encapsulated JavaScript error object.
func (err *Error) Error() string {
	return "JavaScript error: " + err.Get("message").Str()
}

// Global gives JavaScript's global object ("window" for browsers and "GLOBAL" for Node.js). Set this to a mock for testing with pure Go.
var Global Object

// This gives the value of JavaScript's "this" keyword. It can be used when passing Go functions to JavaScript as callbacks. Set this to a mock for testing with pure Go.
var This Object

// Arguments gives the value of JavaScript's "arguments" keyword. It can be used when passing Go functions to JavaScript as callbacks. Set this to a mock for testing with pure Go.
var Arguments []Object

// Module gives the value of the "module" variable set by Node.js.
var Module Object

// Returns the internal JavaScript object that represents i. Not intended for public use.
func InternalObject(i interface{}) Object {
	return nil
}

func init() {
	// avoid dead code elimination of Error
	e := Error{}
	_ = e
}
<commit_msg>Fix a couple typos in js.go comments.<commit_after>// Package js provides functions for interacting with native JavaScript APIs. Calls to these functions are treated specially by GopherJS and translated directly to their JavaScript syntax.
//
// Type conversions between Go types and JavaScript types are performed automatically according to the following table:
//
//  | Go types                       | Go interface type              | JavaScript type |
//  | ------------------------------ | ------------------------------ | --------------- |
//  | bool                           | bool                           | Boolean         |
//  | int?, uint?, float?            | float64                        | Number          |
//  | string                         | string                         | String          |
//  | [?]int8                        | []int8                         | Int8Array       |
//  | [?]int16                       | []int16                        | Int16Array      |
//  | [?]int32, [?]int               | []int                          | Int32Array      |
//  | [?]uint8                       | []uint8                        | Int8Array       |
//  | [?]uint16                      | []uint16                       | Int16Array      |
//  | [?]uint32, [?]uint, [?]uintptr | []uint                         | Int32Array      |
//  | [?]float32                     | []float32                      | Float32Array    |
//  | [?]float64                     | []float64                      | Float64Array    |
//  | all other slices and arrays    | []interface{}                  | Array           |
//  | maps, structs                  | map[string]interface{}         | Object          |
//  | functions                      | func(...interface{}) js.Object | Function        |
//  | time.Time                      | time.Time                      | Date            |
//
// The second column denotes the types that are used when converting to `interface{}`. Additionally, a pointer to a named type is passed to JavaScript as an object which has wrappers for the type's exported methods. This can be used to provide getter and setter methods for Go fields to JavaScript.
package js

// Object is a container for a native JavaScript object. Calls to its methods are treated specially by GopherJS and translated directly to their JavaScript syntax.
type Object interface {

	// Get returns the object's property with the given name.
	Get(name string) Object

	// Set assigns the value to the object's property with the given name.
	Set(name string, value interface{})

	// Delete removes the object's property with the given name.
	Delete(name string)

	// Get returns the object's "length" property, converted to int.
	Length() int

	// Index returns the i'th element of an array.
	Index(i int) Object

	// SetIndex sets the i'th element of an array.
	SetIndex(i int, value interface{})

	// Call calls the object's method with the given name.
	Call(name string, args ...interface{}) Object

	// Invoke calls the object itself. This will fail if it is not a function.
	Invoke(args ...interface{}) Object

	// New creates a new instance of this type object. This will fail if it not a function (constructor).
	New(args ...interface{}) Object

	// Bool returns the object converted to bool according to JavaScript type conversions.
	Bool() bool

	// Str returns the object converted to string according to JavaScript type conversions. Does not implement fmt.Stringer on purpose.
	Str() string

	// Int returns the object converted to int according to JavaScript type conversions (parseInt).
	Int() int

	// Int64 returns the object converted to int64 according to JavaScript type conversions (parseInt).
	Int64() int64

	// Uint64 returns the object converted to uint64 according to JavaScript type conversions (parseInt).
	Uint64() uint64

	// Float returns the object converted to float64 according to JavaScript type conversions (parseFloat).
	Float() float64

	// Interface returns the object converted to interface{}. See GopherJS' README for details.
	Interface() interface{}

	// Unsafe returns the object as an uintptr, which can be converted via unsafe.Pointer. Not intended for public use.
	Unsafe() uintptr

	// IsUndefined returns true if the object is the JavaScript value "undefined".
	IsUndefined() bool

	// IsNull returns true if the object is the JavaScript value "null".
	IsNull() bool
}

// Error encapsulates JavaScript errors. Those are turned into a Go panic and may be rescued, giving an *Error that holds the JavaScript error object.
type Error struct {
	Object
}

// Error returns the message of the encapsulated JavaScript error object.
func (err *Error) Error() string {
	return "JavaScript error: " + err.Get("message").Str()
}

// Global gives JavaScript's global object ("window" for browsers and "GLOBAL" for Node.js). Set this to a mock for testing with pure Go.
var Global Object

// This gives the value of JavaScript's "this" keyword. It can be used when passing Go functions to JavaScript as callbacks. Set this to a mock for testing with pure Go.
var This Object

// Arguments gives the value of JavaScript's "arguments" keyword. It can be used when passing Go functions to JavaScript as callbacks. Set this to a mock for testing with pure Go.
var Arguments []Object

// Module gives the value of the "module" variable set by Node.js.
var Module Object

// Returns the internal JavaScript object that represents i. Not intended for public use.
func InternalObject(i interface{}) Object {
	return nil
}

func init() {
	// avoid dead code elimination of Error
	e := Error{}
	_ = e
}
<|endoftext|>


<commit_before>package pipoint

import (
	"bytes"
	"fmt"
	"net/http"
	"reflect"
	"strings"

	"github.com/fsnotify/fsnotify"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/expfmt"
	"github.com/spf13/viper"
)

type ParamListener func(p *Param)

// Params is a group of parameters that can be listened to.
type Params struct {
	name      string
	viper     *viper.Viper
	params    []*Param
	listeners []ParamListener
}

func NewParams(name string) *Params {
	ps := &Params{
		name:  name,
		viper: viper.New(),
	}

	ps.viper.SetConfigName(name)
	ps.viper.AddConfigPath(".")
	ps.viper.ReadInConfig()
	ps.viper.WatchConfig()
	ps.viper.OnConfigChange(func(e fsnotify.Event) { ps.Load() })

	return ps
}

// Create a new Param in this group.  The Param is uninitialised and
// invalid.
func (ps *Params) New(name string) *Param {
	p := &Param{
		name:   name,
		params: ps,
	}
	ps.params = append(ps.params, p)
	return p
}

// Create a new, valid Param in this group using the given value.
func (ps *Params) NewWith(name string, value interface{}) *Param {
	p := &Param{
		name:   name,
		params: ps,
	}
	p.Set(value)
	ps.params = append(ps.params, p)
	return p
}

func (ps *Params) updated(p *Param) {
	for _, l := range ps.listeners {
		l(p)
	}
}

// Listen to changes on any parameter in this group.
func (ps *Params) Listen(l ParamListener) {
	ps.listeners = append(ps.listeners, l)
}

func (ps *Params) Walk(visitor func(*Param)) {
	for _, p := range ps.params {
		visitor(p)
	}
}

type LeafVisitor func(p *Param, path []string, value reflect.Value)

func (ps *Params) WalkLeaves(visitor LeafVisitor) {
	for _, p := range ps.params {
		ps.visitOne(p, visitor, []string{ps.name, p.name}, reflect.ValueOf(p.Get()))
	}
}

func makeName(path []string, sep string) string {
	name := strings.Join(path, ".")
	return strings.Replace(strings.ToLower(name), ".", sep, -1)
}

func (ps *Params) visitOne(p *Param, visitor LeafVisitor, path []string, v reflect.Value) {
	switch v.Kind() {
	case reflect.Ptr, reflect.Interface:
		ps.visitOne(p, visitor, path, v.Elem())
	case reflect.Struct:
		t := v.Type()
		for i := 0; i < v.NumField(); i++ {
			ps.visitOne(p, visitor, append(path, t.Field(i).Name), v.Field(i))
		}
	default:
		visitor(p, path, v)
	}
}

// Respond with the Prometheus and Params as metrics.
func (ps *Params) Metrics(w http.ResponseWriter, req *http.Request) {
	var buf bytes.Buffer
	enc := expfmt.NewEncoder(&buf, expfmt.FmtText)
	mfs, err := prometheus.DefaultGatherer.Gather()

	if err == nil {
		for _, mf := range mfs {
			enc.Encode(mf)
		}
	}

	ps.WalkLeaves(func(p *Param, path []string, v reflect.Value) {
		name := makeName(path, "_")
		switch v.Kind() {
		case reflect.Invalid:
			break
		case reflect.String:
			if v.String() != "" {
				buf.WriteString(fmt.Sprintf("%s{value=\"%s\"} 1\n", name, v))
			}
		default:
			buf.WriteString(fmt.Sprintf("%s %v\n", name, v))
		}
	})

	header := w.Header()
	header.Set("Content-Type", string(expfmt.FmtText))
	w.Write(buf.Bytes())
}

func (ps *Params) Load() {
	ps.WalkLeaves(func(p *Param, path []string, v reflect.Value) {
		name := makeName(path, ".")
		if !ps.viper.IsSet(name) {
			return
		}
		next := ps.viper.Get(name)
		if v.CanSet() {
			v.Set(reflect.ValueOf(next))
		} else {
			p.Set(next)
		}
	})
}
<commit_msg>params: put the auto metrics at the end of the page.<commit_after>package pipoint

import (
	"bytes"
	"fmt"
	"net/http"
	"reflect"
	"strings"

	"github.com/fsnotify/fsnotify"
	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/common/expfmt"
	"github.com/spf13/viper"
)

type ParamListener func(p *Param)

// Params is a group of parameters that can be listened to.
type Params struct {
	name      string
	viper     *viper.Viper
	params    []*Param
	listeners []ParamListener
}

func NewParams(name string) *Params {
	ps := &Params{
		name:  name,
		viper: viper.New(),
	}

	ps.viper.SetConfigName(name)
	ps.viper.AddConfigPath(".")
	ps.viper.ReadInConfig()
	ps.viper.WatchConfig()
	ps.viper.OnConfigChange(func(e fsnotify.Event) { ps.Load() })

	return ps
}

// Create a new Param in this group.  The Param is uninitialised and
// invalid.
func (ps *Params) New(name string) *Param {
	p := &Param{
		name:   name,
		params: ps,
	}
	ps.params = append(ps.params, p)
	return p
}

// Create a new, valid Param in this group using the given value.
func (ps *Params) NewWith(name string, value interface{}) *Param {
	p := &Param{
		name:   name,
		params: ps,
	}
	p.Set(value)
	ps.params = append(ps.params, p)
	return p
}

func (ps *Params) updated(p *Param) {
	for _, l := range ps.listeners {
		l(p)
	}
}

// Listen to changes on any parameter in this group.
func (ps *Params) Listen(l ParamListener) {
	ps.listeners = append(ps.listeners, l)
}

func (ps *Params) Walk(visitor func(*Param)) {
	for _, p := range ps.params {
		visitor(p)
	}
}

type LeafVisitor func(p *Param, path []string, value reflect.Value)

func (ps *Params) WalkLeaves(visitor LeafVisitor) {
	for _, p := range ps.params {
		ps.visitOne(p, visitor, []string{ps.name, p.name}, reflect.ValueOf(p.Get()))
	}
}

func makeName(path []string, sep string) string {
	name := strings.Join(path, ".")
	return strings.Replace(strings.ToLower(name), ".", sep, -1)
}

func (ps *Params) visitOne(p *Param, visitor LeafVisitor, path []string, v reflect.Value) {
	switch v.Kind() {
	case reflect.Ptr, reflect.Interface:
		ps.visitOne(p, visitor, path, v.Elem())
	case reflect.Struct:
		t := v.Type()
		for i := 0; i < v.NumField(); i++ {
			ps.visitOne(p, visitor, append(path, t.Field(i).Name), v.Field(i))
		}
	default:
		visitor(p, path, v)
	}
}

// Respond with the Prometheus and Params as metrics.
func (ps *Params) Metrics(w http.ResponseWriter, req *http.Request) {
	var buf bytes.Buffer

	ps.WalkLeaves(func(p *Param, path []string, v reflect.Value) {
		name := makeName(path, "_")
		switch v.Kind() {
		case reflect.Invalid:
			break
		case reflect.String:
			if v.String() != "" {
				buf.WriteString(fmt.Sprintf("%s{value=\"%s\"} 1\n", name, v))
			}
		default:
			buf.WriteString(fmt.Sprintf("%s %v\n", name, v))
		}
	})

	enc := expfmt.NewEncoder(&buf, expfmt.FmtText)
	mfs, err := prometheus.DefaultGatherer.Gather()

	if err == nil {
		for _, mf := range mfs {
			enc.Encode(mf)
		}
	}

	header := w.Header()
	header.Set("Content-Type", string(expfmt.FmtText))
	w.Write(buf.Bytes())
}

func (ps *Params) Load() {
	ps.WalkLeaves(func(p *Param, path []string, v reflect.Value) {
		name := makeName(path, ".")
		if !ps.viper.IsSet(name) {
			return
		}
		next := ps.viper.Get(name)
		if v.CanSet() {
			v.Set(reflect.ValueOf(next))
		} else {
			p.Set(next)
		}
	})
}
<|endoftext|>


<commit_before>package classpath

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

// :(linux/unix) or ;(windows)
const pathListSeparator = string(os.PathListSeparator)

var classNotFoundErr = errors.New("class not found!")

type ClassPath struct {
	ccpe CompoundClassPathEntry
}

func ParseClassPath(cpOption string) *ClassPath {
	if cpOption == "" {
		return &ClassPath{}
	}

	cpOptionSplitted := strings.Split(cpOption, pathListSeparator)
	cpEntries := make([]ClassPathEntry, len(cpOptionSplitted))

	for i, p := range cpOptionSplitted {
		absPath, err := filepath.Abs(p)
		if err == nil {
			cpEntries[i] = parseClassPathEntry(absPath)
		} else {
			// todo
		}
	}

	ccpe := CompoundClassPathEntry{cpEntries}
	return &ClassPath{ccpe}
}

// className: fully/qualified/ClassName
func (self *ClassPath) ReadClassData(className string) (ClassPathEntry, []byte, error) {
	className = className + ".class"
	return self.ccpe.readClassData(className)
}
<commit_msg>rename field<commit_after>package classpath

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

// :(linux/unix) or ;(windows)
const pathListSeparator = string(os.PathListSeparator)

var classNotFoundErr = errors.New("class not found!")

type ClassPath struct {
	compoundEntry CompoundClassPathEntry
}

func ParseClassPath(cpOption string) *ClassPath {
	if cpOption == "" {
		return &ClassPath{}
	}

	cpOptionSplitted := strings.Split(cpOption, pathListSeparator)
	cpEntries := make([]ClassPathEntry, len(cpOptionSplitted))

	for i, p := range cpOptionSplitted {
		absPath, err := filepath.Abs(p)
		if err == nil {
			cpEntries[i] = parseClassPathEntry(absPath)
		} else {
			// todo
		}
	}

	compoundEntry := CompoundClassPathEntry{cpEntries}
	return &ClassPath{compoundEntry}
}

// className: fully/qualified/ClassName
func (self *ClassPath) ReadClassData(className string) (ClassPathEntry, []byte, error) {
	className = className + ".class"
	return self.compoundEntry.readClassData(className)
}
<|endoftext|>


<commit_before>package instructions

import (
    . "jvmgo/any"
    "jvmgo/rtda"
    "jvmgo/rtda/class"
)

// Store into reference array
type aastore struct {NoOperandsInstruction}
func (self *aastore) Execute(thread *rtda.Thread) {
    arrRef, index, val := popOperands(thread)
    refArr := arrRef.Fields().([]*class.Obj)
    checkArrIndex(index, len(refArr))
    // todo
    ref := val.(*class.Obj)
    refArr[index] = ref
}

// Store into byte or boolean array
type bastore struct {NoOperandsInstruction}
func (self *bastore) Execute(thread *rtda.Thread) {
    arrRef, index, val := popOperands(thread)
    byteArr := arrRef.Fields().([]int8)
    checkArrIndex(index, len(byteArr))
    byteArr[index] = val.(int8)
}

// Store into char array
type castore struct {NoOperandsInstruction}
func (self *castore) Execute(thread *rtda.Thread) {
    arrRef, index, val := popOperands(thread)
    charArr := arrRef.Fields().([]uint16)
    checkArrIndex(index, len(charArr))
    charArr[index] = val.(uint16)
}

// Store into double array
type dastore struct {NoOperandsInstruction}
func (self *dastore) Execute(thread *rtda.Thread) {
    arrRef, index, val := popOperands(thread)
    doubleArr := arrRef.Fields().([]float64)
    checkArrIndex(index, len(doubleArr))
    doubleArr[index] = val.(float64)
}

// Store into float array
type fastore struct {NoOperandsInstruction}
func (self *fastore) Execute(thread *rtda.Thread) {
    arrRef, index, val := popOperands(thread)
    floatArr := arrRef.Fields().([]float32)
    checkArrIndex(index, len(floatArr))
    floatArr[index] = val.(float32)
}

// Store into int array
type iastore struct {NoOperandsInstruction}
func (self *iastore) Execute(thread *rtda.Thread) {
    arrRef, index, val := popOperands(thread)
    intArr := arrRef.Fields().([]int32)
    checkArrIndex(index, len(intArr))
    intArr[index] = val.(int32)
}

// Store into long array
type lastore struct {NoOperandsInstruction}
func (self *lastore) Execute(thread *rtda.Thread) {
    arrRef, index, val := popOperands(thread)
    longArr := arrRef.Fields().([]int64)
    checkArrIndex(index, len(longArr))
    longArr[index] = val.(int64)
}

// Store into short array
type sastore struct {NoOperandsInstruction}
func (self *sastore) Execute(thread *rtda.Thread) {
    arrRef, index, val := popOperands(thread)
    shortArr := arrRef.Fields().([]int16)
    checkArrIndex(index, len(shortArr))
    shortArr[index] = val.(int16)
}

func popOperands(thread *rtda.Thread) (*class.Obj, int, Any) {
    stack := thread.CurrentFrame().OperandStack()
    val := stack.Pop()
    index := int(stack.PopInt())
    arrRef := stack.PopRef()
    if arrRef == nil {
        // todo
        panic("NullPointerException")
    }
    return arrRef, index, val
}
<commit_msg>fix bastore, castore, sastore<commit_after>package instructions

import (
    . "jvmgo/any"
    "jvmgo/rtda"
    "jvmgo/rtda/class"
)

// Store into reference array
type aastore struct {NoOperandsInstruction}
func (self *aastore) Execute(thread *rtda.Thread) {
    arrRef, index, val := popOperands(thread)
    refArr := arrRef.Fields().([]*class.Obj)
    checkArrIndex(index, len(refArr))
    // todo
    ref := val.(*class.Obj)
    refArr[index] = ref
}

// Store into byte or boolean array
type bastore struct {NoOperandsInstruction}
func (self *bastore) Execute(thread *rtda.Thread) {
    arrRef, index, val := popOperands(thread)
    byteArr := arrRef.Fields().([]int8)
    checkArrIndex(index, len(byteArr))
    byteArr[index] = int8(val.(int32))
}

// Store into char array
type castore struct {NoOperandsInstruction}
func (self *castore) Execute(thread *rtda.Thread) {
    arrRef, index, val := popOperands(thread)
    charArr := arrRef.Fields().([]uint16)
    checkArrIndex(index, len(charArr))
    charArr[index] = uint16(val.(int32))
}

// Store into double array
type dastore struct {NoOperandsInstruction}
func (self *dastore) Execute(thread *rtda.Thread) {
    arrRef, index, val := popOperands(thread)
    doubleArr := arrRef.Fields().([]float64)
    checkArrIndex(index, len(doubleArr))
    doubleArr[index] = val.(float64)
}

// Store into float array
type fastore struct {NoOperandsInstruction}
func (self *fastore) Execute(thread *rtda.Thread) {
    arrRef, index, val := popOperands(thread)
    floatArr := arrRef.Fields().([]float32)
    checkArrIndex(index, len(floatArr))
    floatArr[index] = val.(float32)
}

// Store into int array
type iastore struct {NoOperandsInstruction}
func (self *iastore) Execute(thread *rtda.Thread) {
    arrRef, index, val := popOperands(thread)
    intArr := arrRef.Fields().([]int32)
    checkArrIndex(index, len(intArr))
    intArr[index] = val.(int32)
}

// Store into long array
type lastore struct {NoOperandsInstruction}
func (self *lastore) Execute(thread *rtda.Thread) {
    arrRef, index, val := popOperands(thread)
    longArr := arrRef.Fields().([]int64)
    checkArrIndex(index, len(longArr))
    longArr[index] = val.(int64)
}

// Store into short array
type sastore struct {NoOperandsInstruction}
func (self *sastore) Execute(thread *rtda.Thread) {
    arrRef, index, val := popOperands(thread)
    shortArr := arrRef.Fields().([]int16)
    checkArrIndex(index, len(shortArr))
    shortArr[index] = int16(val.(int32))
}

func popOperands(thread *rtda.Thread) (*class.Obj, int, Any) {
    stack := thread.CurrentFrame().OperandStack()
    val := stack.Pop()
    index := int(stack.PopInt())
    arrRef := stack.PopRef()
    if arrRef == nil {
        // todo
        panic("NullPointerException")
    }
    return arrRef, index, val
}
<|endoftext|>


<commit_before>package revok

import (
	"cred-alert/db"
	"cred-alert/gitclient"
	"cred-alert/kolsch"
	"cred-alert/metrics"
	"cred-alert/scanners"
	"cred-alert/scanners/diffscanner"
	"cred-alert/scanners/dirscanner"
	"cred-alert/sniff"
	"encoding/json"
	"os"
	"path/filepath"
	"strings"
	"time"

	"code.cloudfoundry.org/clock"
	"code.cloudfoundry.org/lager"
)

const successMetric = "revok.success_jobs"
const failedMetric = "revok.failed_jobs"

type worker struct {
	logger               lager.Logger
	clock                clock.Clock
	workdir              string
	ghClient             GitHubClient
	gitClient            gitclient.Client
	sniffer              sniff.Sniffer
	interval             time.Duration
	scanRepository       db.ScanRepository
	repositoryRepository db.RepositoryRepository
	fetchRepository      db.FetchRepository
	successCounter       metrics.Counter
	failedCounter        metrics.Counter
}

func New(
	logger lager.Logger,
	clock clock.Clock,
	workdir string,
	ghClient GitHubClient,
	gitClient gitclient.Client,
	sniffer sniff.Sniffer,
	interval time.Duration,
	scanRepository db.ScanRepository,
	repositoryRepository db.RepositoryRepository,
	fetchRepository db.FetchRepository,
	emitter metrics.Emitter,
) *worker {
	return &worker{
		logger:               logger,
		clock:                clock,
		ghClient:             ghClient,
		gitClient:            gitClient,
		sniffer:              sniffer,
		interval:             interval,
		scanRepository:       scanRepository,
		repositoryRepository: repositoryRepository,
		fetchRepository:      fetchRepository,
		workdir:              workdir,
		successCounter:       emitter.Counter(successMetric),
		failedCounter:        emitter.Counter(failedMetric),
	}
}

func (w *worker) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	logger := w.logger.Session("revok")
	logger.Info("started")

	close(ready)

	timer := w.clock.NewTicker(w.interval)

	defer func() {
		logger.Info("done")
		timer.Stop()
	}()

	w.work(logger)

	for {
		select {
		case <-timer.C():
			w.work(logger)
		case <-signals:
			return nil
		}
	}

	return nil
}

func (w *worker) work(logger lager.Logger) {
	logger = logger.Session("doing-work")
	defer logger.Info("done")

	repos, err := w.ghClient.ListRepositories(logger)
	if err != nil {
		logger.Error("failed-listing-repositories", err)
		return
	}

	quietLogger := kolsch.NewLogger()

	for _, repo := range repos {
		dest := filepath.Join(w.workdir, repo.Owner, repo.Name)

		repoLogger := logger.WithData(lager.Data{
			"owner":       repo.Owner,
			"repository":  repo.Name,
			"destination": dest,
		})

		repository := &db.Repository{
			Owner:         repo.Owner,
			Name:          repo.Name,
			SSHURL:        repo.SSHURL,
			Private:       repo.Private,
			DefaultBranch: repo.DefaultBranch,
			RawJSON:       repo.RawJSON,
			Path:          dest,
		}

		err = w.repositoryRepository.FindOrCreate(repository)
		if err != nil {
			repoLogger.Error("failed-to-find-or-create-repository", err)
			continue
		}

		_, err = os.Lstat(dest)
		if os.IsNotExist(err) {
			err = w.gitClient.Clone(repo.SSHURL, dest)
			if err != nil {
				repoLogger.Error("failed-to-clone", err)
				err = os.RemoveAll(dest)
				if err != nil {
					repoLogger.Error("failed-to-clean-up", err)
				}
				continue
			}

			scan := w.scanRepository.Start(repoLogger, "dir-scan", repository, nil)
			_ = dirscanner.New(handler(scan, repo), w.sniffer).Scan(quietLogger, dest)
			finishScan(repoLogger, scan, w.successCounter, w.failedCounter)
		} else {
			changes, err := w.gitClient.Fetch(dest)
			if err != nil {
				repoLogger.Error("failed-to-fetch", err)
				continue
			}

			bs, err := json.Marshal(changes)
			if err != nil {
				repoLogger.Error("failed-to-marshal-json", err)
			}

			fetch := &db.Fetch{
				Repository: *repository,
				Path:       dest,
				Changes:    bs,
			}

			err = w.fetchRepository.SaveFetch(repoLogger, fetch)
			if err != nil {
				repoLogger.Error("failed-to-save-fetch", err)
				continue
			}

			for _, oids := range changes {
				diff, err := w.gitClient.Diff(dest, oids[0], oids[1])
				if err != nil {
					repoLogger.Error("failed-to-get-diff", err, lager.Data{
						"from": oids[0].String(),
						"to":   oids[1].String(),
					})
					continue
				}

				scan := w.scanRepository.Start(quietLogger, "diff-scan", repository, fetch)
				scanner := diffscanner.NewDiffScanner(strings.NewReader(diff))
				w.sniffer.Sniff(repoLogger, scanner, handler(scan, repo))
				finishScan(repoLogger, scan, w.successCounter, w.failedCounter)
			}
		}
	}
}

func handler(scan db.ActiveScan, repo GitHubRepository) sniff.ViolationHandlerFunc {
	return func(logger lager.Logger, line scanners.Line) error {
		scan.RecordCredential(db.Credential{
			Owner:      repo.Owner,
			Repository: repo.Name,
			Path:       line.Path,
			LineNumber: line.LineNumber,
		})
		return nil
	}
}

func finishScan(logger lager.Logger, scan db.ActiveScan, success, failed metrics.Counter) {
	err := scan.Finish()
	if err != nil {
		failed.Inc(logger)
	} else {
		success.Inc(logger)
	}
}
<commit_msg>Add logging when failing to finish scan<commit_after>package revok

import (
	"cred-alert/db"
	"cred-alert/gitclient"
	"cred-alert/kolsch"
	"cred-alert/metrics"
	"cred-alert/scanners"
	"cred-alert/scanners/diffscanner"
	"cred-alert/scanners/dirscanner"
	"cred-alert/sniff"
	"encoding/json"
	"os"
	"path/filepath"
	"strings"
	"time"

	"code.cloudfoundry.org/clock"
	"code.cloudfoundry.org/lager"
)

const successMetric = "revok.success_jobs"
const failedMetric = "revok.failed_jobs"

type worker struct {
	logger               lager.Logger
	clock                clock.Clock
	workdir              string
	ghClient             GitHubClient
	gitClient            gitclient.Client
	sniffer              sniff.Sniffer
	interval             time.Duration
	scanRepository       db.ScanRepository
	repositoryRepository db.RepositoryRepository
	fetchRepository      db.FetchRepository
	successCounter       metrics.Counter
	failedCounter        metrics.Counter
}

func New(
	logger lager.Logger,
	clock clock.Clock,
	workdir string,
	ghClient GitHubClient,
	gitClient gitclient.Client,
	sniffer sniff.Sniffer,
	interval time.Duration,
	scanRepository db.ScanRepository,
	repositoryRepository db.RepositoryRepository,
	fetchRepository db.FetchRepository,
	emitter metrics.Emitter,
) *worker {
	return &worker{
		logger:               logger,
		clock:                clock,
		ghClient:             ghClient,
		gitClient:            gitClient,
		sniffer:              sniffer,
		interval:             interval,
		scanRepository:       scanRepository,
		repositoryRepository: repositoryRepository,
		fetchRepository:      fetchRepository,
		workdir:              workdir,
		successCounter:       emitter.Counter(successMetric),
		failedCounter:        emitter.Counter(failedMetric),
	}
}

func (w *worker) Run(signals <-chan os.Signal, ready chan<- struct{}) error {
	logger := w.logger.Session("revok")
	logger.Info("started")

	close(ready)

	timer := w.clock.NewTicker(w.interval)

	defer func() {
		logger.Info("done")
		timer.Stop()
	}()

	w.work(logger)

	for {
		select {
		case <-timer.C():
			w.work(logger)
		case <-signals:
			return nil
		}
	}

	return nil
}

func (w *worker) work(logger lager.Logger) {
	logger = logger.Session("doing-work")
	defer logger.Info("done")

	repos, err := w.ghClient.ListRepositories(logger)
	if err != nil {
		logger.Error("failed-listing-repositories", err)
		return
	}

	quietLogger := kolsch.NewLogger()

	for _, repo := range repos {
		dest := filepath.Join(w.workdir, repo.Owner, repo.Name)

		repoLogger := logger.WithData(lager.Data{
			"owner":       repo.Owner,
			"repository":  repo.Name,
			"destination": dest,
		})

		repository := &db.Repository{
			Owner:         repo.Owner,
			Name:          repo.Name,
			SSHURL:        repo.SSHURL,
			Private:       repo.Private,
			DefaultBranch: repo.DefaultBranch,
			RawJSON:       repo.RawJSON,
			Path:          dest,
		}

		err = w.repositoryRepository.FindOrCreate(repository)
		if err != nil {
			repoLogger.Error("failed-to-find-or-create-repository", err)
			continue
		}

		_, err = os.Lstat(dest)
		if os.IsNotExist(err) {
			err = w.gitClient.Clone(repo.SSHURL, dest)
			if err != nil {
				repoLogger.Error("failed-to-clone", err)
				err = os.RemoveAll(dest)
				if err != nil {
					repoLogger.Error("failed-to-clean-up", err)
				}
				continue
			}

			scan := w.scanRepository.Start(repoLogger, "dir-scan", repository, nil)
			_ = dirscanner.New(handler(scan, repo), w.sniffer).Scan(quietLogger, dest)
			finishScan(repoLogger, scan, w.successCounter, w.failedCounter)
		} else {
			changes, err := w.gitClient.Fetch(dest)
			if err != nil {
				repoLogger.Error("failed-to-fetch", err)
				continue
			}

			bs, err := json.Marshal(changes)
			if err != nil {
				repoLogger.Error("failed-to-marshal-json", err)
			}

			fetch := &db.Fetch{
				Repository: *repository,
				Path:       dest,
				Changes:    bs,
			}

			err = w.fetchRepository.SaveFetch(repoLogger, fetch)
			if err != nil {
				repoLogger.Error("failed-to-save-fetch", err)
				continue
			}

			for _, oids := range changes {
				diff, err := w.gitClient.Diff(dest, oids[0], oids[1])
				if err != nil {
					repoLogger.Error("failed-to-get-diff", err, lager.Data{
						"from": oids[0].String(),
						"to":   oids[1].String(),
					})
					continue
				}

				scan := w.scanRepository.Start(quietLogger, "diff-scan", repository, fetch)
				scanner := diffscanner.NewDiffScanner(strings.NewReader(diff))
				w.sniffer.Sniff(repoLogger, scanner, handler(scan, repo))
				finishScan(repoLogger, scan, w.successCounter, w.failedCounter)
			}
		}
	}
}

func handler(scan db.ActiveScan, repo GitHubRepository) sniff.ViolationHandlerFunc {
	return func(logger lager.Logger, line scanners.Line) error {
		scan.RecordCredential(db.Credential{
			Owner:      repo.Owner,
			Repository: repo.Name,
			Path:       line.Path,
			LineNumber: line.LineNumber,
		})
		return nil
	}
}

func finishScan(logger lager.Logger, scan db.ActiveScan, success, failed metrics.Counter) {
	err := scan.Finish()
	if err != nil {
		logger.Error("failed-to-finish-scan", err)
		failed.Inc(logger)
	} else {
		success.Inc(logger)
	}
}
<|endoftext|>


<commit_before>package testings

import (
	"testing"

	"github.com/google/go-cmp/cmp"
)

// AssertEqual ensures that got and want are equal by cmp.Diff.
// If they are not equal, it reports failure by t.Errorf with given `message`.
// If options are empty, it applies default options, which are defined in `defaultCmpOptions`.
// If any options are given, `defaultCmpOptions` are not applied.
func AssertEqual(t *testing.T, want, got interface{}, message string, options ...cmp.Option) {
	t.Helper()
	if diff := cmp.Diff(want, got, options...); diff != "" {
		if message == "" {
			t.Errorf("AssertEqual failed (-want +got):\n%s", diff)
		} else {
			t.Errorf("AssertEqual failed: %q: (-want +got):\n%s", message, diff)
		}
	}
}

// RequireEqual ensures that got and want are equal by cmp.Diff.
// If they are not equal, it reports failure by t.Fatalf with given `message`.
// If options are empty, it applies default options, which are defined in `defaultCmpOptions`.
// If any options are given, `defaultCmpOptions` are not applied.
func RequireEqual(t *testing.T, want, got interface{}, message string, options ...cmp.Option) {
	t.Helper()
	if diff := cmp.Diff(want, got, options...); diff != "" {
		if message == "" {
			t.Fatalf("RequireEqual failed (-want +got):\n%s", diff)
		} else {
			t.Fatalf("RequireEqual failed: %q: (-want +got):\n%s", message, diff)
		}
	}
}
<commit_msg>Update doc comment<commit_after>package testings

import (
	"testing"

	"github.com/google/go-cmp/cmp"
)

// AssertEqual ensures that got and want are equal by cmp.Diff.
// If they are not equal, it reports failure by t.Errorf with given `message`.
func AssertEqual(t *testing.T, want, got interface{}, message string, options ...cmp.Option) {
	t.Helper()
	if diff := cmp.Diff(want, got, options...); diff != "" {
		if message == "" {
			t.Errorf("AssertEqual failed (-want +got):\n%s", diff)
		} else {
			t.Errorf("AssertEqual failed: %q: (-want +got):\n%s", message, diff)
		}
	}
}

// RequireEqual ensures that got and want are equal by cmp.Diff.
// If they are not equal, it reports failure by t.Fatalf with given `message`.
func RequireEqual(t *testing.T, want, got interface{}, message string, options ...cmp.Option) {
	t.Helper()
	if diff := cmp.Diff(want, got, options...); diff != "" {
		if message == "" {
			t.Fatalf("RequireEqual failed (-want +got):\n%s", diff)
		} else {
			t.Fatalf("RequireEqual failed: %q: (-want +got):\n%s", message, diff)
		}
	}
}
<|endoftext|>