func TestFileExpiration(t *testing.T) {
	f := &file{
		contracts: make(map[types.FileContractID]fileContract),
	}
	if f.expiration() != 0 {
		t.Error("file with no pieces should report as having no time remaining")
	}
	fc := fileContract{}
	fc.WindowStart = 100
	f.contracts[types.FileContractID{0}] = fc
	if f.expiration() != 100 {
		t.Error("file did not report lowest WindowStart")
	}
	fc.WindowStart = 50
	f.contracts[types.FileContractID{1}] = fc
	if f.expiration() != 50 {
		t.Error("file did not report lowest WindowStart")
	}
	fc.WindowStart = 75
	f.contracts[types.FileContractID{2}] = fc
	if f.expiration() != 50 {
		t.Error("file did not report lowest WindowStart")
	}
}
TestFileExpiration probes the expiration method of the file type.
package renter
import (
	"os"
	"path/filepath"
	"testing"
	"github.com/NebulousLabs/Sia/modules"
	"github.com/NebulousLabs/Sia/types"
)
func TestFileNumChunks(t *testing.T) {
	tests := []struct {
		size           uint64
		pieceSize      uint64
		piecesPerChunk int
		expNumChunks   uint64
	}{
		{100, 10, 1, 10},  
		{100, 10, 2, 5},   
		{101, 10, 1, 11},  
		{101, 10, 2, 6},   
		{10, 100, 1, 1},  
		{0, 10, 1, 1},    
	}
	for _, test := range tests {
		rsc, _ := NewRSCode(test.piecesPerChunk, 1)  
		f := &file{size: test.size, erasureCode: rsc, pieceSize: test.pieceSize}
		if f.numChunks() != test.expNumChunks {
			t.Errorf("Test %v: expected %v, got %v", test, test.expNumChunks, f.numChunks())
		}
	}
}
func TestFileAvailable(t *testing.T) {
	rsc, _ := NewRSCode(1, 10)
	f := &file{
		size:        1000,
		erasureCode: rsc,
		pieceSize:   100,
	}
	neverOffline := make(map[types.FileContractID]bool)
	if f.available(neverOffline) {
		t.Error("file should not be available")
	}
	var fc fileContract
	for i := uint64(0); i < f.numChunks(); i++ {
		fc.Pieces = append(fc.Pieces, pieceData{Chunk: i, Piece: 0})
	}
	f.contracts = map[types.FileContractID]fileContract{{}: fc}
	if !f.available(neverOffline) {
		t.Error("file should be available")
	}
	specificOffline := make(map[types.FileContractID]bool)
	specificOffline[fc.ID] = true
	if f.available(specificOffline) {
		t.Error("file should not be available")
	}
}
func TestFileUploadedBytes(t *testing.T) {
	f := &file{}
	f.pieceSize = modules.SectorSize / 2
	f.contracts = make(map[types.FileContractID]fileContract)
	f.contracts[types.FileContractID{}] = fileContract{
		ID:     types.FileContractID{},
		IP:     modules.NetAddress(""),
		Pieces: make([]pieceData, 4),
	}
	if f.uploadedBytes() != 4*modules.SectorSize {
		t.Errorf("expected uploadedBytes to be 8, got %v", f.uploadedBytes())
	}
}
func TestFileUploadProgressPinning(t *testing.T) {
	f := &file{}
	f.pieceSize = 2
	f.contracts = make(map[types.FileContractID]fileContract)
	f.contracts[types.FileContractID{}] = fileContract{
		ID:     types.FileContractID{},
		IP:     modules.NetAddress(""),
		Pieces: make([]pieceData, 4),
	}
	rsc, _ := NewRSCode(1, 1)
	f.erasureCode = rsc
	if f.uploadProgress() != 100 {
		t.Fatal("expected uploadProgress to report 100%")
	}
}
func TestFileRedundancy(t *testing.T) {
	nDatas := []int{1, 2, 10}
	neverOffline := make(map[types.FileContractID]bool)
	goodForRenew := make(map[types.FileContractID]bool)
	for i := 0; i < 5; i++ {
		neverOffline[types.FileContractID{byte(i)}] = false
		goodForRenew[types.FileContractID{byte(i)}] = true
	}
	for _, nData := range nDatas {
		rsc, _ := NewRSCode(nData, 10)
		f := &file{
			size:        1000,
			pieceSize:   100,
			contracts:   make(map[types.FileContractID]fileContract),
			erasureCode: rsc,
		}
		if r := f.redundancy(neverOffline, goodForRenew); r != 0 {
			t.Error("expected 0 redundancy, got", r)
		}
		fc := fileContract{
			ID: types.FileContractID{0},
		}
		for i := uint64(0); i < f.numChunks()-1; i++ {
			pd := pieceData{
				Chunk: i,
				Piece: 0,
			}
			fc.Pieces = append(fc.Pieces, pd)
		}
		f.contracts[fc.ID] = fc
		if r := f.redundancy(neverOffline, goodForRenew); r != 0 {
			t.Error("expected 0 redundancy, got", r)
		}
		fc = fileContract{
			ID: types.FileContractID{1},
		}
		for i := uint64(0); i < f.numChunks()-1; i++ {
			pd := pieceData{
				Chunk: i,
				Piece: 1,
			}
			fc.Pieces = append(fc.Pieces, pd)
		}
		f.contracts[fc.ID] = fc
		if r := f.redundancy(neverOffline, goodForRenew); r != 0 {
			t.Error("expected 0 redundancy, got", r)
		}
		fc = fileContract{
			ID: types.FileContractID{2},
		}
		pd := pieceData{
			Chunk: f.numChunks() - 1,
			Piece: 0,
		}
		fc.Pieces = append(fc.Pieces, pd)
		f.contracts[fc.ID] = fc
		expectedR := 1.0 / float64(f.erasureCode.MinPieces())
		if r := f.redundancy(neverOffline, goodForRenew); r != expectedR {
			t.Errorf("expected %f redundancy, got %f", expectedR, r)
		}
		fc = fileContract{
			ID: types.FileContractID{3},
		}
		for iChunk := uint64(0); iChunk < f.numChunks(); iChunk++ {
			for iPiece := uint64(0); iPiece < uint64(f.erasureCode.MinPieces()); iPiece++ {
				fc.Pieces = append(fc.Pieces, pieceData{
					Chunk: iChunk,
					Piece: iPiece + 1,
				})
			}
		}
		f.contracts[fc.ID] = fc
		expectedR = float64(1+f.erasureCode.MinPieces()) / float64(f.erasureCode.MinPieces())
		if r := f.redundancy(neverOffline, goodForRenew); r != expectedR {
			t.Errorf("expected %f redundancy, got %f", expectedR, r)
		}
		fc = fileContract{
			ID: types.FileContractID{4},
		}
		for iChunk := uint64(0); iChunk < f.numChunks(); iChunk++ {
			for iPiece := uint64(0); iPiece < uint64(f.erasureCode.MinPieces()); iPiece++ {
				fc.Pieces = append(fc.Pieces, pieceData{
					Chunk: iChunk,
					Piece: iPiece,
				})
			}
		}
		f.contracts[fc.ID] = fc
		specificOffline := make(map[types.FileContractID]bool)
		for fcid := range goodForRenew {
			specificOffline[fcid] = false
		}
		specificOffline[fc.ID] = true
		if r := f.redundancy(specificOffline, goodForRenew); r != expectedR {
			t.Errorf("expected redundancy to ignore offline file contracts, wanted %f got %f", expectedR, r)
		}
	}
}