<file_sep>package proj2

// CS 161 Project 2

// You MUST NOT change these default imports.  ANY additional imports it will
// break the autograder and everyone will be sad.

import (
	"github.com/cs161-staff/userlib"

	// The JSON library will be useful for serializing go structs.
	// See: https://cs161.org/assets/projects/2/docs/coding_tips/json.html.
	"encoding/json"

	// Likewise, useful for debugging, etc.
	"encoding/hex"

	// The Datastore requires UUIDs to store key-value entries.
	// See: https://cs161.org/assets/projects/2/docs/coding_tips/uuid.html.
	"github.com/google/uuid"

	// Useful for debug messages, or string manipulation for datastore keys.
	"strings"

	// Want to import errors.
	"errors"

	// Optional. You can remove the "_" there, but please do not touch
	// anything else within the import bracket.
	_ "strconv"
	// if you are looking for fmt, we don't give you fmt, but you can use userlib.DebugMsg.
	// see someUsefulThings() below:
)

// This serves two purposes:
// a) It shows you some useful primitives, and
// b) it suppresses warnings for items not being imported.
// Of course, this function can be deleted.
func someUsefulThings() {
	// Creates a random UUID
	f := uuid.New()
	userlib.DebugMsg("UUID as string:%v", f.String())

	// Example of writing over a byte of f
	f[0] = 10
	userlib.DebugMsg("UUID as string:%v", f.String())

	// takes a sequence of bytes and renders as hex
	h := hex.EncodeToString([]byte("fubar"))
	userlib.DebugMsg("The hex: %v", h)

	// Marshals data into a JSON representation
	// Will actually work with go structures as well
	d, _ := json.Marshal(f)
	userlib.DebugMsg("The json data: %v", string(d))
	var g uuid.UUID
	json.Unmarshal(d, &g)
	userlib.DebugMsg("Unmashaled data %v", g.String())

	// This creates an error type
	userlib.DebugMsg("Creation of error %v", errors.New(strings.ToTitle("This is an error")))

	// And a random RSA key.  In this case, ignoring the error
	// return value
	var pk userlib.PKEEncKey
	var sk userlib.PKEDecKey
	pk, sk, _ = userlib.PKEKeyGen()
	userlib.DebugMsg("Key is %v, %v", pk, sk)
}

// Helper function: Takes the first 16 bytes and converts it into the UUID type
func bytesToUUID(data []byte) (ret uuid.UUID) {
	for x := range ret {
		ret[x] = data[x]
	}
	return
}

type Node struct {
	Username        string
	User_invite_loc []byte //encrypted with the root/owner's public key
	Children        []*Node
}

type LL_node struct {
	Data      userlib.UUID
	HMAC_Data []byte
	Next      userlib.UUID
}

type Tree struct {
	Root *Node
}

// User is the structure definition for a user record.
type User struct {
	password   string
	Username   string
	Tree_sk    userlib.PKEDecKey
	Secret_key userlib.PKEDecKey
	Signing_sk userlib.DSSignKey
	Files_key  []byte
	//Files       userlib.UUID // pointer to Hashmap of files: filename → accesstoken|HMAC(file_location)
}

type File struct {
	//Data         []byte
	// End_pointer  int  //encrypted int len of file
	Head         userlib.UUID
	Tail         userlib.UUID
	Participants Tree
	File_ID      []byte
}

type AccessToken struct {
	Enc_file_symm     []byte
	Enc_file_id       []byte
	Enc_file_owner    []byte
	Enc_recipient			[]byte
	Signed_file_symm  []byte
	Signed_file_id    []byte
	Signed_file_owner []byte
	Signed_recipient	[]byte
	// Enc_keys    []byte
	// Signed_keys []byte
}

func Find(slice []uuid.UUID, val uuid.UUID) (found bool) {
	for _, item := range slice {
		if item == val {
			return true
		}
	}
	return false
}

func Padding(msg []byte) (padded_msg []byte) {
	msg_len := len(msg)
	padding := 16 - msg_len%16
	for i := 0; i < padding; i += 1 {
		msg = append(msg, byte(padding))
	}
	return msg
}

func Unpad(ciphertext []byte) (unpadded_msg []byte) {
	padding := int(ciphertext[len(ciphertext)-1])
	unpadded_msg = ciphertext[0 : len(ciphertext)-padding]
	return unpadded_msg
}

func CheckMult16(text []byte) (mult bool) {
	if len(text) > 16 {
		if len(text)%16 == 0 {
			return true
		}
	}
	return false
}

func CheckRange(text []byte) (mult bool) {
	if text[len(text)-1] > 16 || text[len(text)-1] < 1 {
		return false
	}
	return true
}

func TreeSearch(participants *Tree, username string) (node *Node) {
	queue := make([]*Node, 0)
	queue = append(queue, participants.Root)

	for len(queue) > 0 {
		next := queue[0]
		queue = queue[1:]
		if next.Username == username {
			return next
		}
		if len(next.Children) > 0 {
			for _, child := range next.Children {
				queue = append(queue, child)
			}
		}
	}

	return nil
}

func RetrieveHashmap(username string, files_key []byte) (files map[string]userlib.UUID, err error) {

	hash := userlib.Hash([]byte(username + "files"))
	slicehash := hash[:]
	enc_marshalled_files, _ := userlib.DatastoreGet(bytesToUUID(slicehash))

	hash_HMAC := userlib.Hash([]byte(username + "files HMAC"))
	slicehash_HMAC := hash_HMAC[:]
	enc_marshalled_files_HMAC, _ := userlib.DatastoreGet(bytesToUUID(slicehash_HMAC))

	HMAC_key, _ := userlib.HashKDF(files_key, []byte("HMAC files"))
	HMAC_calc, _ := userlib.HMACEval(HMAC_key[:16], enc_marshalled_files)
	if !userlib.HMACEqual(HMAC_calc, enc_marshalled_files_HMAC) {
		return nil, errors.New(strings.ToTitle("Files HMAC doesn't match."))
	}

	dec_key, _ := userlib.HashKDF(files_key, []byte("encryption files"))
	if !CheckMult16(enc_marshalled_files) {
		return nil, errors.New(strings.ToTitle("File has been corrupted."))
	}
	if !CheckMult16(enc_marshalled_files) {
		return nil, errors.New(strings.ToTitle("Linked list data has been corrupted in RevokeFile."))
	}
	marshalled_files := userlib.SymDec(dec_key[:16], enc_marshalled_files)
	if !CheckRange(marshalled_files) {
		return nil, errors.New(strings.ToTitle("Linked list data is not correctly decrypted."))
	}
	marshalled_files = Unpad(marshalled_files)
	json.Unmarshal(marshalled_files, &files)
	return files, nil
}

func SetHashmap(filename string, accessToken userlib.UUID, username string, files_key []byte) error {
	files, err := RetrieveHashmap(username, files_key)
	if err != nil {
		return err
	}
	files[filename] = accessToken
	files_marshalled, _ := json.Marshal(files)
	files_marshalled = Padding(files_marshalled)
	enc_key, _ := userlib.HashKDF(files_key, []byte("encryption files"))
	files_marshalled_enc := userlib.SymEnc(enc_key[:16], userlib.RandomBytes(16), files_marshalled)
	hash := userlib.Hash([]byte(username + "files"))
	slicehash := hash[:]
	userlib.DatastoreSet(bytesToUUID(slicehash), files_marshalled_enc)

	HMAC_key, _ := userlib.HashKDF(files_key, []byte("HMAC files"))
	files_marshalled_enc_HMAC, _ := userlib.HMACEval(HMAC_key[:16], files_marshalled_enc)
	hash_HMAC := userlib.Hash([]byte(username + "files HMAC"))
	slicehash_HMAC := hash_HMAC[:]
	userlib.DatastoreSet(bytesToUUID(slicehash_HMAC), files_marshalled_enc_HMAC)
	return nil
}

func RetrieveFile(owner_hash []byte, file_symm []byte, file_id []byte) (filedataptr *File, err error) {
	key_hash := userlib.Hash(append(file_id, owner_hash[:]...))
	storageKey, _ := uuid.FromBytes(key_hash[:16])
	dataJSON, ok := userlib.DatastoreGet(storageKey)
	if !ok {
		return nil, errors.New(strings.ToTitle("File not in Datastore!"))
	}
	file_symm_struct, _ := userlib.HashKDF(file_symm, []byte("encrypt struct"))
	file_symm_struct = file_symm_struct[:16]
	if !CheckMult16(dataJSON) {
		return nil, errors.New(strings.ToTitle("File has been corrupted in RetrieveFile."))
	}
	dataJSON_dec := userlib.SymDec(file_symm_struct, dataJSON)
	if !CheckRange(dataJSON_dec) {
		return nil, errors.New(strings.ToTitle("Linked list data is not correctly decrypted."))
	}
	dataJSON_dec = Unpad(dataJSON_dec)
	var filedata File
	filedataptr = &filedata
	json.Unmarshal(dataJSON_dec, filedataptr)

	hmac := []byte("HMAC")
	key_HMAC := append(hmac, owner_hash...)
	key_HMAC = append(file_id, key_HMAC...)
	key_hash_HMAC := userlib.Hash(key_HMAC)
	storageKey_HMAC, _ := uuid.FromBytes(key_hash_HMAC[:16])
	filedata_HMAC, ok := userlib.DatastoreGet(storageKey_HMAC)
	if !ok {
		return nil, errors.New(strings.ToTitle("File HMAC not in Datastore!"))
	}
	file_symm_struct_HMAC, _ := userlib.HashKDF(file_symm, []byte("HMAC struct"))
	file_symm_struct_HMAC = file_symm_struct_HMAC[:16]
	filedata_HMAC_datastore, _ := userlib.HMACEval(file_symm_struct_HMAC, dataJSON)
	if !userlib.HMACEqual(filedata_HMAC, filedata_HMAC_datastore) {
		return nil, errors.New(strings.ToTitle("File HMACs don't match!"))
	}

	return filedataptr, nil
}

func RetrieveAccessToken(userdata *User, filename string) (file_symm []byte, file_id []byte, file_owner_hash []byte,
	owner []byte, err error) {
	files, err := RetrieveHashmap(userdata.Username, userdata.Files_key)
	if err != nil {
		return nil, nil, nil, nil, err
	}
	uuid_accessToken, ok := files[filename]
	if !ok {
		return nil, nil, nil, nil, errors.New(strings.ToTitle("Access token not in hashmap!"))
	}
	accessToken_marshaled, ok := userlib.DatastoreGet(uuid_accessToken)
	if !ok {
		return nil, nil, nil, nil, errors.New(strings.ToTitle("Access Token not in Datastore"))
	}

	secret_key := userdata.Secret_key
	var AT AccessToken
	_ = json.Unmarshal(accessToken_marshaled, &AT)

	file_symm, _ = userlib.PKEDec(secret_key, AT.Enc_file_symm)
	// invalid := []byte("This is an invalid accessToken.")
	// if string(file_symm) == string(invalid) {
	// 	return nil, nil, nil, nil, errors.New(strings.ToTitle("This user does not have a valid accessToken." + string(file_symm)))
	// }
	file_id, _ = userlib.PKEDec(secret_key, AT.Enc_file_id)
	owner, _ = userlib.PKEDec(secret_key, AT.Enc_file_owner)
	file_owner := userlib.Hash(owner)
	file_owner_hash = file_owner[:]

	return file_symm, file_id, file_owner_hash, owner, nil
}

func DatastoreFile(file_id []byte, owner_hash []byte, file_symm []byte, filedata *File) {
	//Storing encrypted file struct in datastore
	key_hash := userlib.Hash(append(file_id, owner_hash[:]...))
	storageKey, _ := uuid.FromBytes(key_hash[:16])
	jsonData, _ := json.Marshal(filedata)
	jsonData_enc := Padding(jsonData)
	iv := userlib.RandomBytes(16)
	file_symm_struct, _ := userlib.HashKDF(file_symm, []byte("encrypt struct"))
	file_symm_struct = file_symm_struct[:16]
	jsonData_enc = userlib.SymEnc(file_symm_struct, iv, jsonData_enc)
	userlib.DatastoreSet(storageKey, jsonData_enc)

	//Storing encrypted file struct HMAC in datastore
	hmac := []byte("HMAC")
	key_HMAC := append(hmac, owner_hash[:]...)
	key_HMAC = append(file_id, key_HMAC...)
	key_hash_HMAC := userlib.Hash(key_HMAC)
	storageKey_HMAC, _ := uuid.FromBytes(key_hash_HMAC[:16])
	file_symm_struct_HMAC, _ := userlib.HashKDF(file_symm, []byte("HMAC struct"))
	file_symm_struct_HMAC = file_symm_struct_HMAC[:16]
	jsonData_enc_HMAC, _ := userlib.HMACEval(file_symm_struct_HMAC, jsonData_enc) //maybe don't use file_symm
	userlib.DatastoreSet(storageKey_HMAC, jsonData_enc_HMAC)
}

func DatastoreUser(userdata *User, pk userlib.PKEEncKey) {
	userbytes, _ := json.Marshal(userdata)
	pwd_bytes := []byte(userdata.password)

	//Storing encrypted user struct in datastore
	IV_enc := userlib.RandomBytes(16)
	userbytes = Padding(userbytes)

	pk_salt, _ := userlib.KeystoreGet(userdata.Username + "_salt")
	salt_marshalled, _ := json.Marshal(pk_salt)
	salt, _ := userlib.HMACEval(salt_marshalled[:16], []byte(userdata.Username))

	userdata_enc := userlib.SymEnc(userlib.Argon2Key(pwd_bytes, salt, 32), IV_enc, userbytes)
	hash := userlib.Hash([]byte(userdata.Username))
	slicehash := hash[:]
	userlib.DatastoreSet(bytesToUUID(slicehash), userdata_enc)

	//Storing HMAC of encrypted user struct in datastore
	userdata_HMAC, _ := userlib.HMACEval(userlib.Argon2Key(pwd_bytes, salt, 16), userdata_enc)
	hash_HMAC := userlib.Hash([]byte(userdata.Username + "HMAC"))
	slicehash_HMAC := hash_HMAC[:]
	userlib.DatastoreSet(bytesToUUID(slicehash_HMAC), userdata_HMAC)
}

// InitUser will be called a single time to initialize a new user.
func InitUser(username string, password string) (userdataptr *User, err error) {
	var userdata User
	userdataptr = &userdata

	//TODO: This is a toy implementation.
	user_enckey := username + "_enckey"
	//Check if username already exists
	_, ok := userlib.KeystoreGet(user_enckey)
	if ok {
		return nil, errors.New(strings.ToTitle("Username already exists."))
	}

	if len(username) <= 0 {
		return nil, errors.New(strings.ToTitle("Username length is not valid."))
	}
	if len(password) <= 0 {
		return nil, errors.New(strings.ToTitle("Password length is not valid."))
	}

	userdata.Username = username
	pwd_bytes := []byte(<PASSWORD>)

	public_key, secret_key, _ := userlib.PKEKeyGen()

	//TODO: Check keylen later if necessary - secret keys using keylen = 32, hmacs using keylen = 16
	userlib.KeystoreSet(user_enckey, public_key)

	userdata.Secret_key = secret_key
	pk_salt, _, _ := userlib.PKEKeyGen()
	userlib.KeystoreSet(username+"_salt", pk_salt)
	salt_marshalled, _ := json.Marshal(pk_salt)
	salt, _ := userlib.HMACEval(salt_marshalled[:16], []byte(username))

	Tree_pk, Tree_sk, _ := userlib.PKEKeyGen()
	userlib.KeystoreSet(username+"_treekey", Tree_pk)
	userdata.Tree_sk = Tree_sk

	signing_sk, signing_verk, _ := userlib.DSKeyGen()

	user_verkey := username + "_verkey"
	userlib.KeystoreSet(user_verkey, signing_verk)

	userdata.Signing_sk = signing_sk
	userdata.Files_key = userlib.RandomBytes(16)

	//initialize empty files hashmap and store in datastore
	files := make(map[string]userlib.UUID)
	files_marshalled, _ := json.Marshal(files)
	files_marshalled = Padding(files_marshalled)
	enc_key, _ := userlib.HashKDF(userdata.Files_key, []byte("encryption files"))
	files_marshalled_enc := userlib.SymEnc(enc_key[:16], userlib.RandomBytes(16), files_marshalled)
	hash := userlib.Hash([]byte(username + "files"))
	slicehash := hash[:]
	userlib.DatastoreSet(bytesToUUID(slicehash), files_marshalled_enc)

	HMAC_key, _ := userlib.HashKDF(userdata.Files_key, []byte("HMAC files"))
	files_marshalled_enc_HMAC, _ := userlib.HMACEval(HMAC_key[:16], files_marshalled_enc)
	hash_HMAC := userlib.Hash([]byte(username + "files HMAC"))
	slicehash_HMAC := hash_HMAC[:]
	userlib.DatastoreSet(bytesToUUID(slicehash_HMAC), files_marshalled_enc_HMAC)

	userbytes, _ := json.Marshal(userdata)
	//Storing encrypted user struct in datastore
	IV_enc := userlib.RandomBytes(16)
	userbytes = Padding(userbytes)
	userdata_enc := userlib.SymEnc(userlib.Argon2Key(pwd_bytes, salt, 32), IV_enc, userbytes)
	hash = userlib.Hash([]byte(username))
	slicehash = hash[:]
	userlib.DatastoreSet(bytesToUUID(slicehash), userdata_enc)

	//Storing HMAC of encrypted user struct in datastore
	userdata_HMAC, _ := userlib.HMACEval(userlib.Argon2Key(pwd_bytes, salt, 16), userdata_enc)
	hash_HMAC = userlib.Hash([]byte(username + "HMAC"))
	slicehash_HMAC = hash_HMAC[:]
	userlib.DatastoreSet(bytesToUUID(slicehash_HMAC), userdata_HMAC)

	userdata.password = <PASSWORD>

	return &userdata, nil
}

// GetUser is documented at:
// https://cs161.org/assets/projects/2/docs/client_api/getuser.html
func GetUser(username string, password string) (userdataptr *User, err error) {
	var userdata User
	userdataptr = &userdata

	user_enckey := username + "_enckey"
	user_verkey := username + "_verkey"

	_, ok_enc := userlib.KeystoreGet(user_enckey)
	_, ok_sign := userlib.KeystoreGet(user_verkey)

	if ok_enc && ok_sign {
		hash := userlib.Hash([]byte(username))
		slicehash := hash[:]
		user, ok := userlib.DatastoreGet(bytesToUUID(slicehash))

		if !ok {
			return nil, errors.New(strings.ToTitle("Username does not exist."))
		}

		hash_HMAC := userlib.Hash([]byte(username + "HMAC"))
		slicehash_HMAC := hash_HMAC[:]
		user_HMAC_datastore, _ := userlib.DatastoreGet(bytesToUUID(slicehash_HMAC))

		pk_salt, _ := userlib.KeystoreGet(username + "_salt")
		salt_marshalled, _ := json.Marshal(pk_salt)
		salt, _ := userlib.HMACEval(salt_marshalled[:16], []byte(username))

		pwd_bytes := []byte(<PASSWORD>)
		user_HMAC, _ := userlib.HMACEval(userlib.Argon2Key(pwd_bytes, salt, 16), user)

		if !userlib.HMACEqual(user_HMAC, user_HMAC_datastore) {
			return nil, errors.New(strings.ToTitle("HMAC of user structs don't match."))
		}
		if !CheckMult16(user) {
			return nil, errors.New(strings.ToTitle("User has been corrupted in GetUser."))
		}
		user = userlib.SymDec(userlib.Argon2Key(pwd_bytes, salt, 32), user)
		if !CheckRange(user) {
			return nil, errors.New(strings.ToTitle("User data is not correctly decrypted."))
		}
		user = Unpad(user)
		_ = json.Unmarshal(user, userdataptr)

		userdata.password = <PASSWORD>

		return userdataptr, nil

	} else {
		return nil, errors.New(strings.ToTitle("User has not been initialized."))
	}

}

// StoreFile is documented at:
// https://cs161.org/assets/projects/2/docs/client_api/storefile.html
func (userdata *User) StoreFile(filename string, data []byte) (err error) {

	// file_symm: HMAC data, encrypt data, HMAC file struct, encrypt file struct
	var filedata File

	data = Padding(data)

	// case where file exists and someone else may be owner and we are overwriting
	files, err := RetrieveHashmap(userdata.Username, userdata.Files_key)
	if err != nil {
		return err
	}
	_, ok := files[filename]
	if ok {
		file_symm, file_id, file_owner_hash, _, err1 := RetrieveAccessToken(userdata, filename)
		if err1 != nil {
			return err1
		}
		filedata, _ := RetrieveFile(file_owner_hash, file_symm, file_id)

		var data_node LL_node
		iv := userlib.RandomBytes(16)
		file_symm_data, _ := userlib.HashKDF(file_symm, []byte("encrypt data"))
		file_symm_data = file_symm_data[:16]
		location := uuid.New()
		enc_d := userlib.SymEnc(file_symm_data, iv, data)
		userlib.DatastoreSet(location, enc_d)
		data_node.Data = location
		file_symm_data_HMAC, _ := userlib.HashKDF(file_symm, []byte("HMAC data"))
		file_symm_data_HMAC = file_symm_data_HMAC[:16]
		data_node.HMAC_Data, _ = userlib.HMACEval(file_symm_data_HMAC, enc_d)
		data_node.Next = uuid.Nil

		random := userlib.RandomBytes(16)
		data_loc := bytesToUUID(random)

		data_node_marshal, _ := json.Marshal(data_node)
		userlib.DatastoreSet(data_loc, data_node_marshal)

		head, _ := userlib.DatastoreGet(filedata.Head)
		var linked_list LL_node
		json.Unmarshal(head, &linked_list)
		loc := filedata.Head
		for linked_list.Next != uuid.Nil {
			ll_data, _ := userlib.DatastoreGet(linked_list.Data)
			calc_HMAC, _ := userlib.HMACEval(file_symm_data_HMAC, ll_data)
			if string(calc_HMAC) != string(linked_list.HMAC_Data) {
				return errors.New(strings.ToTitle("File contents have been corrupted."))
			}

			next, _ := userlib.DatastoreGet(linked_list.Next)
			json.Unmarshal(next, &linked_list)

			userlib.DatastoreDelete(loc)
			loc = linked_list.Next
		}
		userlib.DatastoreDelete(loc)

		filedata.Head = data_loc
		filedata.Tail = data_loc

		DatastoreFile(file_id, file_owner_hash, file_symm, filedata)
		return
	}

	file_symm := userlib.RandomBytes(16)

	var data_node LL_node //needs to go onto datastore
	iv := userlib.RandomBytes(16)
	file_symm_data, _ := userlib.HashKDF(file_symm, []byte("encrypt data"))
	file_symm_data = file_symm_data[:16]
	location := uuid.New()
	enc_d := userlib.SymEnc(file_symm_data, iv, data)
	userlib.DatastoreSet(location, enc_d)
	data_node.Data = location
	file_symm_data_HMAC, _ := userlib.HashKDF(file_symm, []byte("HMAC data"))
	file_symm_data_HMAC = file_symm_data_HMAC[:16]
	data_node.HMAC_Data, _ = userlib.HMACEval(file_symm_data_HMAC, enc_d)
	data_node.Next = uuid.Nil

	data_loc := uuid.New()

	data_node_marshal, _ := json.Marshal(data_node)
	userlib.DatastoreSet(data_loc, data_node_marshal)

	filedata.Head = data_loc
	filedata.Tail = data_loc

	pk, _ := userlib.KeystoreGet(userdata.Username + "_enckey")
	file_id := userlib.RandomBytes(16)
	filedata.File_ID = file_id

	owner_hash := userlib.Hash([]byte(userdata.Username))

	signing_sk := userdata.Signing_sk

	// user_hash := userlib.Hash(append([]byte(userdata.Username), []byte("accessToken")...))
	// key_hash := userlib.Hash(append(file_id, user_hash[:]...))

	accessToken := uuid.New()
	encrypted_file_symm, _ := userlib.PKEEnc(pk, file_symm)
	encrypted_file_id, _ := userlib.PKEEnc(pk, file_id)
	encrypted_file_owner, _ := userlib.PKEEnc(pk, []byte(userdata.Username))

	signed_enc_file_symm, _ := userlib.DSSign(signing_sk, encrypted_file_symm)
	signed_enc_file_id, _ := userlib.DSSign(signing_sk, encrypted_file_id)
	signed_enc_file_owner, _ := userlib.DSSign(signing_sk, encrypted_file_owner)

	var encrypted_AT_struct AccessToken
	encrypted_AT_struct.Enc_file_symm = encrypted_file_symm
	encrypted_AT_struct.Enc_file_id = encrypted_file_id
	encrypted_AT_struct.Enc_file_owner = encrypted_file_owner
	encrypted_AT_struct.Signed_file_symm = signed_enc_file_symm
	encrypted_AT_struct.Signed_file_id = signed_enc_file_id
	encrypted_AT_struct.Signed_file_owner = signed_enc_file_owner
	encrypted_AT_marshaled, _ := json.Marshal(encrypted_AT_struct)

	userlib.DatastoreSet(accessToken, encrypted_AT_marshaled)

	// Encrypting file with Tree_pk
	Tree_pk, _ := userlib.KeystoreGet(userdata.Username + "_treekey")
	SetHashmap(filename, accessToken, userdata.Username, userdata.Files_key)
	//userdata.Files[filename] = accessToken
	invite_AT, _ := json.Marshal(accessToken)
	invite_AT_enc, _ := userlib.PKEEnc(Tree_pk, invite_AT)

	var usernode Node
	usernodeptr := &usernode
	usernode.Username = userdata.Username
	usernode.User_invite_loc = invite_AT_enc
	usernode.Children = nil

	var participants Tree
	participants.Root = usernodeptr
	filedata.Participants = participants

	DatastoreFile(file_id, owner_hash[:], file_symm, &filedata)
	DatastoreUser(userdata, pk)
	return
}

//AppendFile is documented at:
//https://cs161.org/assets/projects/2/docs/client_api/appendfile.html
func (userdata *User) AppendFile(filename string, data []byte) (err error) {

	if data == nil || len(data) < 1 {
		return errors.New(strings.ToTitle("No data to append."))
	}

	file_symm, file_id, file_owner_hash, _, err := RetrieveAccessToken(userdata, filename)
	if err != nil {
		return err
	}

	filedata, err := RetrieveFile(file_owner_hash, file_symm, file_id)
	if err != nil {
		return err
	}

	participants := filedata.Participants
	if TreeSearch(&participants, userdata.Username) == nil {
		return errors.New(strings.ToTitle("User does not have access to this file."))
	}

	// Create new node for new Data and place in Datstore at data_loc
	var data_node LL_node
	iv := userlib.RandomBytes(16)
	data = Padding(data)

	file_symm_data, _ := userlib.HashKDF(file_symm, []byte("encrypt data"))
	file_symm_data = file_symm_data[:16]
	file_symm_data_HMAC, _ := userlib.HashKDF(file_symm, []byte("HMAC data"))
	file_symm_data_HMAC = file_symm_data_HMAC[:16]

	location := uuid.New()
	enc_d := userlib.SymEnc(file_symm_data, iv, data)
	userlib.DatastoreSet(location, enc_d)
	data_node.Data = location
	data_node.HMAC_Data, _ = userlib.HMACEval(file_symm_data_HMAC, enc_d)
	data_node.Next = uuid.Nil

	random := userlib.RandomBytes(16)
	data_loc := bytesToUUID(random)

	data_node_marshal, _ := json.Marshal(data_node)
	userlib.DatastoreSet(data_loc, data_node_marshal)
	///////////////////

	//old tail Next should point to new data node
	tail, _ := userlib.DatastoreGet(filedata.Tail)
	var tail_ll LL_node
	json.Unmarshal(tail, &tail_ll)
	tail_ll.Next = data_loc
	tail_marshal, _ := json.Marshal(tail_ll)
	userlib.DatastoreSet(filedata.Tail, tail_marshal)
	//////////////

	filedata.Tail = data_loc
	DatastoreFile(file_id, file_owner_hash, file_symm, filedata)
	return nil
}

// LoadFile is documented at:
// https://cs161.org/assets/projects/2/docs/client_api/loadfile.html
func (userdata *User) LoadFile(filename string) (dataBytes []byte, err error) {

	file_symm, file_id, file_owner_hash, _, err := RetrieveAccessToken(userdata, filename)
	if err != nil {
		return nil, err
	}

	filedata, err := RetrieveFile(file_owner_hash, file_symm, file_id)
	if err != nil {
		return nil, err
	}

	participants := filedata.Participants

	if TreeSearch(&participants, userdata.Username) == nil {
		return nil, errors.New(strings.ToTitle("User does not have access to this file."))
	}

	file_id_str := string(file_id)

	if file_id_str != string(filedata.File_ID) {
		return nil, errors.New(strings.ToTitle("Did not retrieve the correct file (wrong file id)."))
	}

	head, _ := userlib.DatastoreGet(filedata.Head)
	var linked_list LL_node
	json.Unmarshal(head, &linked_list)
	dataBytes = []byte{}

	file_symm_data, _ := userlib.HashKDF(file_symm, []byte("encrypt data"))
	file_symm_data = file_symm_data[:16]
	file_symm_data_HMAC, _ := userlib.HashKDF(file_symm, []byte("HMAC data"))
	file_symm_data_HMAC = file_symm_data_HMAC[:16]
	visited := []uuid.UUID{filedata.Head}
	found := Find(visited, linked_list.Next)
	curr_uuid := filedata.Head

	for linked_list.Next != uuid.Nil && !found {
		ll_data, _ := userlib.DatastoreGet(linked_list.Data)
		calc_HMAC, _ := userlib.HMACEval(file_symm_data_HMAC, ll_data)
		if string(calc_HMAC) != string(linked_list.HMAC_Data) {
			return nil, errors.New(strings.ToTitle("File contents have been corrupted."))
		}
		if !CheckMult16(ll_data) {
			return nil, errors.New(strings.ToTitle("Linked list data has been corrupted in LoadFile."))
		}
		data := userlib.SymDec(file_symm_data, ll_data)
		if !CheckRange(data) {
			return nil, errors.New(strings.ToTitle("Linked list data is not correctly decrypted."))
		}
		data = Unpad(data)
		dataBytes = append(dataBytes, data...)

		// checking for loops and proper termination and advancing to the next node
		visited = append(visited, linked_list.Next)
		next, _ := userlib.DatastoreGet(linked_list.Next)
		curr_uuid = linked_list.Next
		json.Unmarshal(next, &linked_list)
		found = Find(visited, linked_list.Next)
	}
	if !found {
		if curr_uuid != filedata.Tail {
			return nil, errors.New(strings.ToTitle("Did not complete going through the data."))
		}
		ll_data, _ := userlib.DatastoreGet(linked_list.Data)
		calc_HMAC, _ := userlib.HMACEval(file_symm_data_HMAC, ll_data)
		if string(calc_HMAC) != string(linked_list.HMAC_Data) {
			return nil, errors.New(strings.ToTitle("File contents have been corrupted."))
		}
		if !CheckMult16(ll_data) {
			return nil, errors.New(strings.ToTitle("Linked list data has been corrupted in LoadFile."))
		}
		data := userlib.SymDec(file_symm_data, ll_data)
		if !CheckRange(data) {
			return nil, errors.New(strings.ToTitle("Linked list data is not correctly decrypted."))
		}
		data = Unpad(data)
		dataBytes = append(dataBytes, data...)
	} else {
		return nil, errors.New(strings.ToTitle("Cycle detected in data."))
	}

	return dataBytes, nil
}

// ShareFile is documented at:
// https://cs161.org/assets/projects/2/docs/client_api/sharefile.html
func (userdata *User) ShareFile(filename string, recipient string) (
	accessToken uuid.UUID, err error) {
	file_symm, file_id, file_owner_hash, owner, err := RetrieveAccessToken(userdata, filename)
	if err != nil {
		return uuid.Nil, err
	}
	filedata, err := RetrieveFile(file_owner_hash, file_symm, file_id)
	if err != nil {
		return uuid.Nil, err
	}
	participants := filedata.Participants

	if TreeSearch(&participants, userdata.Username) == nil {
		return uuid.Nil, errors.New(strings.ToTitle("This user does not have access to the file."))
	}
	if TreeSearch(&participants, recipient) != nil {
		return uuid.Nil, errors.New(strings.ToTitle("This recipient already has access to the file."))
	}
	recipient_pk, ok := userlib.KeystoreGet(recipient + "_enckey")
	if !ok {
		return uuid.Nil, errors.New(strings.ToTitle("Recipient username is incorrect."))
	}

	signing_sk := userdata.Signing_sk

	encrypted_file_symm, _ := userlib.PKEEnc(recipient_pk, file_symm)
	encrypted_file_id, _ := userlib.PKEEnc(recipient_pk, file_id)
	encrypted_file_owner, _ := userlib.PKEEnc(recipient_pk, owner)
	encrypted_recipient, _ := userlib.PKEEnc(recipient_pk, []byte(recipient))
	signed_enc_file_symm, _ := userlib.DSSign(signing_sk, encrypted_file_symm)
	signed_enc_file_id, _ := userlib.DSSign(signing_sk, encrypted_file_id)
	signed_enc_file_owner, _ := userlib.DSSign(signing_sk, encrypted_file_owner)
	signed_recipient, _ := userlib.DSSign(signing_sk, encrypted_recipient)

	var encrypted_AT_struct AccessToken
	encrypted_AT_struct.Enc_file_symm = encrypted_file_symm
	encrypted_AT_struct.Enc_file_id = encrypted_file_id
	encrypted_AT_struct.Enc_file_owner = encrypted_file_owner
	encrypted_AT_struct.Enc_recipient = encrypted_recipient
	encrypted_AT_struct.Signed_file_symm = signed_enc_file_symm
	encrypted_AT_struct.Signed_file_id = signed_enc_file_id
	encrypted_AT_struct.Signed_file_owner = signed_enc_file_owner
	encrypted_AT_struct.Signed_recipient = signed_recipient
	encrypted_AT_marshaled, _ := json.Marshal(encrypted_AT_struct)

	accessToken = uuid.New()

	userlib.DatastoreSet(accessToken, encrypted_AT_marshaled)

	Tree_pk, _ := userlib.KeystoreGet(string(owner) + "_treekey")
	invite_AT, _ := json.Marshal(accessToken)
	invite_AT_enc, _ := userlib.PKEEnc(Tree_pk, invite_AT)

	var usernode Node
	usernode.Username = recipient
	usernode.User_invite_loc = invite_AT_enc
	usernode.Children = nil

	// set this user to be child of sender
	sender_node := TreeSearch(&participants, userdata.Username)
	if sender_node == nil {
		return uuid.Nil, errors.New(strings.ToTitle("Sender does not have access to the file."))
	}
	sender_node.Children = append(sender_node.Children, &usernode)

	DatastoreFile(file_id, file_owner_hash, file_symm, filedata)

	return accessToken, nil
}

// ReceiveFile is documented at:
// https://cs161.org/assets/projects/2/docs/client_api/receivefile.html
func (userdata *User) ReceiveFile(filename string, sender string,
	accessToken uuid.UUID) error {

	files, err := RetrieveHashmap(userdata.Username, userdata.Files_key)
	if err != nil {
		return err
	}
	_, ok := files[filename]
	if ok {
		// share after revoke puts access token exactly where it was before making, this method useless
		_, _, _, _, err := RetrieveAccessToken(userdata, filename)
		if err == nil {
			return errors.New(strings.ToTitle("This user already has a file with filename:" + filename))
		}
	}

	accessToken_enc, _ := userlib.DatastoreGet(accessToken)

	var AT AccessToken
	_ = json.Unmarshal(accessToken_enc, &AT)

	sender_verkey, _ := userlib.KeystoreGet(sender + "_verkey")
	err = userlib.DSVerify(sender_verkey, AT.Enc_file_symm, AT.Signed_file_symm)
	if err != nil {
		return err
	}
	err = userlib.DSVerify(sender_verkey, AT.Enc_file_id, AT.Signed_file_id)
	if err != nil {
		return err
	}
	err = userlib.DSVerify(sender_verkey, AT.Enc_file_owner, AT.Signed_file_owner)
	if err != nil {
		return err
	}
	err = userlib.DSVerify(sender_verkey, AT.Enc_recipient, AT.Signed_recipient)
	if err != nil {
		return err
	}
	recipient_sk := userdata.Secret_key
	intended_recipient, _ := userlib.PKEDec(recipient_sk, AT.Enc_recipient)
	if string(intended_recipient) != userdata.Username {
		return errors.New(strings.ToTitle("This user is not the intended recipient."))
	}
	SetHashmap(filename, accessToken, userdata.Username, userdata.Files_key)

	return nil
}

// RevokeFile is documented at:
// https://cs161.org/assets/projects/2/docs/client_api/revokefile.html
func (userdata *User) RevokeFile(filename string, targetUsername string) (err error) {
	file_symm, file_id, file_owner_hash, owner, err := RetrieveAccessToken(userdata, filename)
	if err != nil {
		return err
	}
	filedata, err := RetrieveFile(file_owner_hash, file_symm, file_id)
	if err != nil {
		return err
	}
	if targetUsername == userdata.Username {
		return errors.New(strings.ToTitle("Owner cannot revoke from themself."))
	}
	participants := filedata.Participants
	if (participants.Root).Username != userdata.Username {
		return errors.New(strings.ToTitle("User does not have revoke access."))
	}
	targetNode := TreeSearch(&participants, targetUsername)
	if targetNode == nil {
		return errors.New(strings.ToTitle("Target does not currently have access to this file."))
	}

	Tree_sk := userdata.Tree_sk

	// go through pariticipants and replace file_symm
	file_symm_new := userlib.RandomBytes(16)
	//affected by  file_symm: encryption of data, HMAC of data, encryption of filestruct, HMAC of filestruct

	head, _ := userlib.DatastoreGet(filedata.Head)
	var linked_list LL_node
	json.Unmarshal(head, &linked_list)

	file_symm_data, _ := userlib.HashKDF(file_symm, []byte("encrypt data"))
	file_symm_data = file_symm_data[:16]
	file_symm_data_HMAC, _ := userlib.HashKDF(file_symm, []byte("HMAC data"))
	file_symm_data_HMAC = file_symm_data_HMAC[:16]

	file_symm_new_data, _ := userlib.HashKDF(file_symm_new, []byte("encrypt data"))
	file_symm_new_data = file_symm_new_data[:16]
	file_symm_new_data_HMAC, _ := userlib.HashKDF(file_symm_new, []byte("HMAC data"))
	file_symm_new_data_HMAC = file_symm_new_data_HMAC[:16]

	location := filedata.Head
	for linked_list.Next != uuid.Nil {
		ll_data, _ := userlib.DatastoreGet(linked_list.Data)
		calc_HMAC, _ := userlib.HMACEval(file_symm_data_HMAC, ll_data)
		if string(calc_HMAC) != string(linked_list.HMAC_Data) {
			return errors.New(strings.ToTitle("File contents have been corrupted in revoke."))
		}
		if !CheckMult16(ll_data) {
			return errors.New(strings.ToTitle("Linked list data has been corrupted in RevokeFile."))
		}
		data := userlib.SymDec(file_symm_data, ll_data)
		iv := userlib.RandomBytes(16)
		data = userlib.SymEnc(file_symm_new_data, iv, data)
		data_HMAC, _ := userlib.HMACEval(file_symm_new_data_HMAC, data)
		location_data := uuid.New()
		userlib.DatastoreSet(location_data, data)
		linked_list.Data = location_data
		linked_list.HMAC_Data = data_HMAC
		ll_marshalled, _ := json.Marshal(linked_list)
		userlib.DatastoreSet(location, ll_marshalled)
		next, _ := userlib.DatastoreGet(linked_list.Next)
		location = linked_list.Next
		json.Unmarshal(next, &linked_list)
	}
	ll_data, _ := userlib.DatastoreGet(linked_list.Data)
	calc_HMAC, _ := userlib.HMACEval(file_symm_data_HMAC, ll_data)
	if string(calc_HMAC) != string(linked_list.HMAC_Data) {
		return errors.New(strings.ToTitle("File contents have been corrupted in revoke end."))
	}
	if !CheckMult16(ll_data) {
		return errors.New(strings.ToTitle("Linked list data has been corrupted in RevokeFile."))
	}
	data := userlib.SymDec(file_symm_data, ll_data)
	iv := userlib.RandomBytes(16)
	data = userlib.SymEnc(file_symm_new_data, iv, data)
	data_HMAC, _ := userlib.HMACEval(file_symm_new_data_HMAC, data)
	location_data := uuid.New()
	userlib.DatastoreSet(location_data, data)
	linked_list.Data = location_data
	linked_list.HMAC_Data = data_HMAC
	ll_marshalled, _ := json.Marshal(linked_list)
	userlib.DatastoreSet(location, ll_marshalled)

	// for the for subtree of target user, change accessTokens to garbage
	invalid := []byte("This is an invalid accessToken.")
	updateAccessTokens(targetNode, invalid, userlib.RandomBytes(16), userlib.RandomBytes(10), Tree_sk, true)

	// remove subtree for this node in participants (probably create this helper)
	removeSubtree(&participants, targetNode.Username)

	updateAccessTokens(participants.Root, file_symm_new, file_id, owner, Tree_sk, false)

	DatastoreFile(file_id, file_owner_hash, file_symm_new, filedata)
	return
}

// iterates through node and all it's children and updates their accessTokens with given udpate_val
// encrypts the update_val according to who the node belongs to
func updateAccessTokens(node *Node, file_symm []byte, file_id []byte, file_owner []byte, owner_sk userlib.PKEDecKey, delete bool) (err error) {
	if node == nil {
		return nil
	}
	node_pk, _ := userlib.KeystoreGet(node.Username + "_enckey")

	encrypted_file_symm, _ := userlib.PKEEnc(node_pk, file_symm)
	encrypted_file_id, _ := userlib.PKEEnc(node_pk, file_id)
	encrypted_file_owner, _ := userlib.PKEEnc(node_pk, file_owner)
	signed_enc_file_symm := userlib.RandomBytes(256)
	signed_enc_file_id := userlib.RandomBytes(256)
	signed_enc_file_owner := userlib.RandomBytes(256)

	var encrypted_AT_struct AccessToken
	encrypted_AT_struct.Enc_file_symm = encrypted_file_symm
	encrypted_AT_struct.Enc_file_id = encrypted_file_id
	encrypted_AT_struct.Enc_file_owner = encrypted_file_owner
	encrypted_AT_struct.Signed_file_symm = signed_enc_file_symm
	encrypted_AT_struct.Signed_file_id = signed_enc_file_id
	encrypted_AT_struct.Signed_file_owner = signed_enc_file_owner
	encrypted_AT_marshaled, _ := json.Marshal(encrypted_AT_struct)

	AT, _ := userlib.PKEDec(owner_sk, node.User_invite_loc)
	var AT_uuid uuid.UUID
	json.Unmarshal(AT, &AT_uuid)
	userlib.DatastoreSet(AT_uuid, encrypted_AT_marshaled)

	if delete {
		userlib.DatastoreDelete(AT_uuid)
		_, ok := userlib.DatastoreGet(AT_uuid)
		if ok {
			return errors.New(strings.ToTitle("AT_uuid was not deleted from datastore."))
		}
	}

	for _, child := range node.Children {
		updateAccessTokens(child, file_symm, file_id, file_owner, owner_sk, delete)
	}
	return nil
}

func removeSubtree(participants *Tree, targetUser string) (found bool) {
	queue := make([]*Node, 0)
	queue = append(queue, participants.Root)
	for len(queue) > 0 {
		next := queue[0]
		queue = queue[1:]
		if len(next.Children) > 0 {
			for idx, child := range next.Children {
				if child.Username == targetUser {
					if len(next.Children) == 1 {
						next.Children = nil
					} else {
						next.Children = append(next.Children[:idx], next.Children[idx+1:]...)

					}
					return true
				}
				queue = append(queue, child)
			}
		}
	}

	return false
}
<file_sep>package proj2

// You MUST NOT change these default imports.  ANY additional imports it will
// break the autograder and everyone will be sad.

import (
	_ "encoding/hex"
	_ "errors"
	"reflect"
	_ "strconv"
	_ "strings"
	"testing"

	"github.com/cs161-staff/userlib"
	"github.com/google/uuid"
	_ "github.com/google/uuid"
)

func clear() {
	// Wipes the storage so one test does not affect another
	userlib.DatastoreClear()
	userlib.KeystoreClear()
}

func TestInit(t *testing.T) {
	clear()
	t.Log("Initialization test")

	// You can set this to false!
	userlib.SetDebugStatus(true)

	u, err := InitUser("alice", "fubar")
	if err != nil {
		// t.Error says the test fails
		t.Error("Failed to initialize user", err)
		return
	}
	// t.Log() only produces output if you run with "go test -v"
	t.Log("Got user", u)
	// If you want to comment the line above,
	// write _ = u here to make the compiler happy
	// You probably want many more tests here.

	u, err = InitUser("alice", "pingpong")
	if err == nil {
		// t.Error says the test fails
		t.Error("Failed to recognize a taken username", err)
		return
	}

	u, err = InitUser("Alice", "pingpong")
	if err != nil {
		// t.Error says the test fails
		t.Error("Failed to be case sensitive to usernames", err)
		return
	}

	u, err = InitUser("AliCe", "pingpong")
	if err != nil {
		// t.Error says the test fails
		t.Error("Failed to be case sensitive to usernames", err)
		return
	}

	u, err = InitUser("", "pingpong")
	if err == nil {
		// t.Error says the test fails
		t.Error("Failed to recognize an invalid empty username", err)
		return
	}

	u, err = InitUser("bob", "<PASSWORD>ong")
	if err != nil {
		// t.Error says the test fails
		t.Error("Failed to successfully create new user", err)
		return
	}
}

func TestGet(t *testing.T) {
	clear()
	t.Log("GetUser test")

	// You can set this to false!
	userlib.SetDebugStatus(true)

	_, err := InitUser("alice", "fubar")
	if err != nil {
		// t.Error says the test fails
		t.Error("Failed to initialize user", err)
		return
	}

	_, e := GetUser("alice", "fubar")

	if e != nil {
		t.Error("Failed to get user", e)
		return
	}

	_, e = GetUser("alice", "kkkk")

	if e == nil {
		t.Error("Failed to recognize wrong password.", e)
		return
	}

	_, e = GetUser("alicea", "fubar")

	if e == nil {
		t.Error("Failed to recognize wrong username.", e)
		return
	}

	_, e = GetUser("alisce", "kkkk")

	if e == nil {
		t.Error("Failed to recognize wrong username and password.", e)
		return
	}

}

func TestGetUserErrors(t *testing.T) {
	clear()

	_, err := InitUser("alice", "fubar")
	if err != nil {
		// t.Error says the test fails
		t.Error("Failed to initialize user", err)
		return
	}

	_, e := GetUser("alice", "fubar")

	if e != nil {
		t.Error("Failed to get user", e)
		return
	}

	// tamper with datastore
	// datastore := userlib.DatastoreGetMap()
	hash := userlib.Hash([]byte("alice"))
	slicehash := hash[:]
	garbage := userlib.RandomBytes(64)
	uuid_hash, _ := uuid.FromBytes(slicehash[:16])
	userlib.DatastoreSet(uuid_hash, garbage)

	_, e = GetUser("alice", "fubar")

	if e == nil {
		t.Error("Failed to recognize user can't be retrieved.", e)
		return
	}

	//////////////
	clear()

	_, err = InitUser("alice", "fubar")
	if err != nil {
		// t.Error says the test fails
		t.Error("Failed to initialize user", err)
		return
	}

	_, e = GetUser("alice", "fubar")

	if e != nil {
		t.Error("Failed to get user", e)
		return
	}

	// tamper with datastore
	// datastore := userlib.DatastoreGetMap()
	hash = userlib.Hash([]byte("alice" + "HMAC"))
	slicehash = hash[:]
	garbage = userlib.RandomBytes(64)
	uuid_hash, _ = uuid.FromBytes(slicehash[:16])
	userlib.DatastoreSet(uuid_hash, garbage)

	_, e = GetUser("alice", "fubar")

	if e == nil {
		t.Error("Failed to recognize user can't be retrieved.", e)
		return
	}
}

func TestRetrieveHashmapErrors(t *testing.T) {
	clear()

	u, err := InitUser("alice", "fubar")
	if err != nil {
		// t.Error says the test fails
		t.Error("Failed to initialize user", err)
		return
	}

	v := []byte("Test storage")
	e := u.StoreFile("file1", v)

	if e != nil {
		t.Error("Failed to store file", e)
		return
	}

	hash := userlib.Hash([]byte("alice" + "files"))
	slicehash := hash[:]
	garbage := userlib.RandomBytes(64)
	uuid_hash, _ := uuid.FromBytes(slicehash[:16])
	userlib.DatastoreSet(uuid_hash, garbage)

	v = []byte("Test overwriting with storage")
	e = u.StoreFile("file1", v)

	if e == nil {
		t.Error("Failed to store file", e)
		return
	}

	//////////////
	clear()

	u, err = InitUser("alice", "fubar")
	if err != nil {
		// t.Error says the test fails
		t.Error("Failed to initialize user", err)
		return
	}

	v = []byte("Test storage")
	e = u.StoreFile("file1", v)

	if e != nil {
		t.Error("Failed to store file", e)
		return
	}

	hash = userlib.Hash([]byte("alice" + "files HMAC"))
	slicehash = hash[:]
	garbage = userlib.RandomBytes(64)
	uuid_hash, _ = uuid.FromBytes(slicehash[:16])
	userlib.DatastoreSet(uuid_hash, garbage)

	v = []byte("Test overwriting with storage")
	e = u.StoreFile("file1", v)

	if e == nil {
		t.Error("Failed to store file", e)
		return
	}
}

func TestMultipleUserSessions(t *testing.T) {
	clear()

	_, err := InitUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}

	alice1, err := GetUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to get user", err)
		return
	}

	alice2, err := GetUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to get user", err)
		return
	}

	if !reflect.DeepEqual(alice1, alice2) {
		t.Error("Alice1 and Alice2 don't point to the same thing", alice1, alice2)
		return
	}

	// alice1 creates a file
	v := []byte("This is a test")
	err1 := alice1.StoreFile("file1", v)
	if err1 != nil {
		t.Error("Alice1 failed to store.", err1)
		return
	}

	v2, err2 := alice1.LoadFile("file1")
	if err2 != nil {
		t.Error("Alice1 failed to download", err2)
		return
	}

	// alice2 can load the file
	v2, err2 = alice2.LoadFile("file1")
	if err2 != nil {
		t.Error("Alice2 failed to download", err2)
		return
	}
	if !reflect.DeepEqual(v, v2) {
		t.Error("Alice2's downloaded file is not the same", v, v2)
		return
	}

	// alice2 appends to the file
	err = alice2.AppendFile("file1", []byte("Appending to file."))
	if err != nil {
		t.Error("Alice2 failed to append", err)
	}

	// alice1 can load the appended file
	v1, err1 := alice1.LoadFile("file1")
	if err1 != nil {
		t.Error("Alice1 failed to download", err1)
		return
	}
	expected_v := []byte("This is a testAppending to file.")
	if !reflect.DeepEqual(expected_v, v1) {
		t.Error("Alice1's downloaded file is not the same", expected_v, v1)
		return
	}

	// alice1 shares file to bob
	bob, _ := InitUser("bob", "<PASSWORD>")

	accessToken, err := alice1.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Alice1 failed to share file1 with bob", err)
		return
	}

	err = bob.ReceiveFile("file1", "alice", accessToken)
	if err != nil {
		t.Error("Bob failed to receive file1 from Alice", err)
		return
	}

	// bob appends to file
	err = bob.AppendFile("file1", []byte("Bob appending here."))
	if err != nil {
		t.Error("Bob failed to append to file1", err)
		return
	}

	bob_v, err1 := bob.LoadFile("file1")
	if err1 != nil {
		t.Error("Bob failed to download", err1)
		return
	}

	expected_v = []byte("This is a testAppending to file.Bob appending here.")
	if !reflect.DeepEqual(expected_v, bob_v) {
		t.Error("Bob's downloaded file is not the same", expected_v, bob_v)
		return
	}

	// alice1 and alice 2 can load the appended file

	alice1_v, err1 := alice1.LoadFile("file1")
	if err1 != nil {
		t.Error("Alice1 failed to download", err1)
		return
	}

	if !reflect.DeepEqual(expected_v, alice1_v) {
		t.Error("Alice1's downloaded file is not the same", expected_v, alice1_v)
		return
	}

	alice2_v, err1 := alice2.LoadFile("file1")
	if err1 != nil {
		t.Error("Alice2 failed to download", err1)
		return
	}

	if !reflect.DeepEqual(expected_v, alice2_v) {
		t.Error("Alice2's downloaded file is not the same", expected_v, alice2_v)
		return
	}
}

func TestMultipleUserSessions_2(t *testing.T) {
	clear()

	_, err := InitUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}

	alice1, err := GetUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to get user", err)
		return
	}

	alice2, err := GetUser("alice", "fbar")
	if err == nil {
		t.Error("Failed to recognize wrong password second session", err)
		return
	}

	alice2, err = GetUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to get user", err)
		return
	}
	v := []byte("This is my file")
	alice1.StoreFile("file1", v)

	_, err = InitUser("bob", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}

	bob1, err := GetUser("bob", "fubar")
	if err != nil {
		t.Error("Failed to get user", err)
		return
	}

	bob2, err := GetUser("bob", "fubar")
	if err != nil {
		t.Error("Failed to get user", err)
		return
	}

	accessToken, err := alice2.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Alice2 failed to share file1 with bob", err)
		return
	}

	err = bob1.ReceiveFile("file1", "alice", accessToken)
	if err != nil {
		t.Error("Bob1 failed to reeive from Alice2", err)
		return
	}

	bob_v := []byte("Bob2 appending")
	err = bob2.AppendFile("file1", bob_v)
	if err != nil {
		t.Error("Bob2 failed to append to file1", err)
		return
	}

	bob_v = []byte("Bob1 appending")
	err = bob1.AppendFile("file1", bob_v)
	if err != nil {
		t.Error("Bob1 failed to append to file1", err)
		return
	}

	alice_v := []byte("Alice1 appending")
	err = alice1.AppendFile("file1", alice_v)
	if err != nil {
		t.Error("Alice1 failed to append to file1", err)
		return
	}

	alice_v = []byte("Alice2 appending")
	err = alice2.AppendFile("file1", alice_v)
	if err != nil {
		t.Error("Alice2 failed to append to file1", err)
		return
	}

	data_bob1, err := bob1.LoadFile("file1")
	if err != nil {
		t.Error("Bob1 failed to load file1", err)
		return
	}

	expected_v := []byte("This is my fileBob2 appendingBob1 appendingAlice1 appendingAlice2 appending")
	if !reflect.DeepEqual(data_bob1, expected_v) {
		t.Error("files are not equal", data_bob1, expected_v)
		return
	}

	data_alice2, err := alice2.LoadFile("file1")
	if err != nil {
		t.Error("Alice2 failed to load file1", err)
		return
	}

	if !reflect.DeepEqual(data_alice2, expected_v) {
		t.Error("files are not equal", data_alice2, expected_v)
		return
	}

	//alice1 revoke from bob2
	err = alice1.RevokeFile("file1", "bob")
	if err != nil {
		t.Error("Alice1 failed to revoke from Bob.", err)
		return
	}

	_, err = alice2.LoadFile("file1")
	if err != nil {
		t.Error("Alice2 failed to load file1", err)
		return
	}
}

func TestStorage(t *testing.T) {
	clear()
	u, err := InitUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}

	v := []byte("This is a test")
	err1 := u.StoreFile("file1", v)
	if err1 != nil {
		t.Error("Failed to store.", err1)
		return
	}

	v2, err2 := u.LoadFile("file1")
	if err2 != nil {
		t.Error("Failed to upload and download", err2)
		return
	}
	if !reflect.DeepEqual(v, v2) {
		t.Error("Downloaded file is not the same", v, v2)
		return
	}

	u1, _ := InitUser("bob", "<PASSWORD>")
	_, err3 := u1.LoadFile("file1")
	if err3 == nil {
		t.Error("Did not detect invalid load.", err3)
		return
	}

	_, err4 := u.LoadFile("file2")
	if err4 == nil {
		t.Error("Did not detect file DNE.", err4)
		return
	}

	v3 := []byte("This better overwrite")
	err5 := u.StoreFile("file1", v3)
	if err5 != nil {
		t.Error("Failed to overwrite.", err5)
		return
	}

	v4, err5 := u.LoadFile("file1")
	if err5 != nil {
		t.Error("Failed to upload and download", err5)
		return
	}
	if !reflect.DeepEqual(v3, v4) {
		t.Error("Downloaded file is not the same", v3, v4)
		return
	}
}

func TestInvalidFile(t *testing.T) {
	clear()
	u, err := InitUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}

	_, err2 := u.LoadFile("this file does not exist")
	if err2 == nil {
		t.Error("Downloaded a ninexistent file", err2)
		return
	}
}

func TestAppend(t *testing.T) {
	clear()
	u, err := InitUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}

	v := []byte("This is a test")
	u.StoreFile("file1", v)

	stored_v, _ := u.LoadFile("file1")
	if !reflect.DeepEqual(v, stored_v) {
		t.Error("not matching: ", string(stored_v))
		return
	}

	err1 := u.AppendFile("file1", []byte(" appended data"))
	if err1 != nil {
		t.Error("Failed to append", err1)
		return
	}

	expected := []byte("This is a test appended data")
	loaded, err2 := u.LoadFile("file1")
	if err2 != nil {
		t.Error("Failed to load appended file", err2)
		return
	}
	if !reflect.DeepEqual(expected, loaded) {
		t.Error("Failed to correctly append ", string(loaded))
		return
	}
}

func TestAppend_NonOwners(t *testing.T) {
	clear()
	u, err := InitUser("alice", "<PASSWORD>")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}

	u2, err2 := InitUser("bob", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}

	u3, err3 := InitUser("charlie", "foobar")
	if err3 != nil {
		t.Error("Failed to initialize bob", err3)
		return
	}

	v := []byte("This is a test")
	u.StoreFile("file1", v)

	accessToken, err := u.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Failed to share the a file", err)
		return
	}

	err = u2.ReceiveFile("file2", "alice", accessToken)
	if err != nil {
		t.Error("Failed to receive the share message", err)
		return
	}

	err = u2.AppendFile("file2", []byte("Appending this data."))
	if err != nil {
		t.Error("Failed to allow non-owner to append", err)
		return
	}

	v2, err := u2.LoadFile("file2")
	if err != nil {
		t.Error("Bob failed to download the file after non-owner appended", err)
		return
	}

	expected_v := []byte("This is a testAppending this data.")
	if !reflect.DeepEqual(expected_v, v2) {
		t.Error("The file bob loaded after appending is incorrect.", expected_v, v2)
		return
	}

	alice_v, err := u.LoadFile("file1")
	if err != nil {
		t.Error("Alice failed to download the file after non-owner appended", err)
		return
	}
	if !reflect.DeepEqual(expected_v, alice_v) {
		t.Error("The file alice loaded after bob (non-owner) appended is incorrect.", expected_v, alice_v)
		return
	}

	accessToken, err = u2.ShareFile("file2", "charlie")
	if err != nil {
		t.Error("Failed to share the a file", err)
		return
	}

	err = u3.ReceiveFile("file3", "bob", accessToken)
	if err != nil {
		t.Error("Failed to receive the share message", err)
		return
	}

	err = u3.AppendFile("file3", []byte("Appending more data."))
	if err != nil {
		t.Error("Failed to allow non-owner (charlie) to append", err)
		return
	}

	err = u3.AppendFile("file3", []byte("AND more data."))
	if err != nil {
		t.Error("Failed to allow non-owner (charlie) to append", err)
		return
	}

	err = u.AppendFile("file1", []byte("AND even more data."))
	if err != nil {
		t.Error("Failed to allow owner Alice to append", err)
		return
	}

	expected_v = []byte("This is a testAppending this data.Appending more data.AND more data.AND even more data.")
	v3, err := u3.LoadFile("file3")
	if err != nil {
		t.Error("Failed to download the file after sharing", err)
		return
	}

	if !reflect.DeepEqual(expected_v, v3) {
		t.Error("Shared file is not the same", v, v3)
		return
	}

	v2, err = u2.LoadFile("file2")
	if err != nil {
		t.Error("Bob failed to download the file after charlie appended", err)
		return
	}

	if !reflect.DeepEqual(expected_v, v2) {
		t.Error("Bob's shared file is not the same", v, v2)
		return
	}

	v1, err := u.LoadFile("file1")
	if err != nil {
		t.Error("Alice failed to download the file after charlie appended", err)
		return
	}

	if !reflect.DeepEqual(expected_v, v1) {
		t.Error("Alice's shared file is not the same", v, v1)
		return
	}
}

func TestShare(t *testing.T) {
	clear()
	u, err := InitUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}
	u2, err2 := InitUser("bob", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}

	v := []byte("This is a test")
	u.StoreFile("file1", v)

	var v2 []byte
	var accessToken uuid.UUID

	v, err = u.LoadFile("file1")
	if err != nil {
		t.Error("Failed to download the file from alice", err)
		return
	}

	accessToken, err = u.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Failed to share the a file", err)
		return
	}

	err = u2.ReceiveFile("file2", "alice", accessToken)
	if err != nil {
		t.Error("Failed to receive the share message", err)
		return
	}

	v2, err = u2.LoadFile("file2")
	if err != nil {
		t.Error("Failed to download the file after sharing", err)
		return
	}
	if !reflect.DeepEqual(v, v2) {
		t.Error("Shared file is not the same", v, v2)
		return
	}
}

func TestOverwrite(t *testing.T) {
	clear()
	// alice stores
	alice, err := InitUser("alice", "<PASSWORD>")
	if err != nil {
		t.Error("Failed to initialize alice", err)
		return
	}
	bob, err2 := InitUser("bob", "<PASSWORD>")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}

	v := []byte("This is a test")
	alice.StoreFile("file1", v)

	var accessToken uuid.UUID

	// alice loads
	v, err = alice.LoadFile("file1")
	if err != nil {
		t.Error("Failed to download the file from alice", err)
		return
	}

	// overwrite
	v = []byte("This is overwriting")
	alice.StoreFile("file1", v)

	// alice loads -- check correctly overwritten
	var v2 []byte
	v2, err = alice.LoadFile("file1")
	if err != nil {
		t.Error("Failed to download the file from alice after overwrite", err)
		return
	}

	if !reflect.DeepEqual(v, v2) {
		t.Error("overwritten file is not the same", v, v2)
		return
	}

	// alice share with Bob
	accessToken, err = alice.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Alice failed to share file with bob", err)
		return
	}

	err = bob.ReceiveFile("file2", "alice", accessToken)
	if err != nil {
		t.Error("Bob failed to receive the share message", err)
		return
	}

	// bob storess
	v = []byte("Bob is overwriting")
	bob.StoreFile("file2", v)

	// alice load -- check correctly overwritten
	v2, err = alice.LoadFile("file1")
	if err != nil {
		t.Error("Failed to download the file from alice after bob overwrites", err)
		return
	}

	if !reflect.DeepEqual(v, v2) {
		t.Error("Shared file is not the same", v, v2)
		return
	}

	// bob load -- check correctly overwritten
	v2, err = bob.LoadFile("file2")
	if err != nil {
		t.Error("Failed to download the file from bob after he overwrites", err)
		return
	}

	if !reflect.DeepEqual(v, v2) {
		t.Error("Shared file is not the same", v, v2)
		return
	}
}

func TestRevoke_1(t *testing.T) {
	clear()

	u, err := InitUser("alice", "<PASSWORD>")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}
	u2, err2 := InitUser("bob", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}

	v := []byte("This is a test")
	u.StoreFile("file1", v)

	var v2 []byte
	var accessToken uuid.UUID

	v, err = u.LoadFile("file1")
	if err != nil {
		t.Error("Failed to download the file from alice", err)
		return
	}

	accessToken, err = u.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Failed to share the a file", err)
		return
	}

	err = u2.ReceiveFile("file1", "alice", accessToken)
	if err != nil {
		t.Error("Failed to receive the share message", err)
		return
	}

	v2, err = u2.LoadFile("file1")
	if err != nil {
		t.Error("Failed to download the file after sharing", err)
		return
	}

	if !reflect.DeepEqual(v, v2) {
		t.Error("Shared file is not the same", v, v2)
		return
	}

	v, err = u.LoadFile("file1")
	if err != nil {
		t.Error("Failed to download the file from alice after share", err)
		return
	}

	err = u.RevokeFile("file1", "bob")
	if err != nil {
		t.Error("Failed to revoke access from bob", err)
		return
	}

	v, err = u.LoadFile("file1")
	if err != nil {
		t.Error("Failed to download the file from alice after revoke", err)
		return
	}

	v2, err = u2.LoadFile("file1")
	if err == nil {
		t.Error("Bob still has access after revocation", err)
		return
	}
}

func TestRevoke_2(t *testing.T) {
	//alice shares with bob & charlie, revoke from charlie, bob should still be able to load
	clear()

	// initalize users
	u, err := InitUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}
	u2, err2 := InitUser("bob", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}
	u3, err3 := InitUser("charlie", "foobar")
	if err3 != nil {
		t.Error("Failed to initialize bob", err3)
		return
	}
	/////////////////

	//alice create file
	v := []byte("This is a test")
	u.StoreFile("file1", v)

	var v2 []byte
	var accessToken uuid.UUID

	v, err = u.LoadFile("file1")
	if err != nil {
		t.Error("Failed to download the file from alice", err)
		return
	}
	//////////////////

	// alice shares with bob
	accessToken, err = u.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Failed to share the a file", err)
		return
	}

	err = u2.ReceiveFile("file2", "alice", accessToken)
	if err != nil {
		t.Error("Failed to receive the share message", err)
		return
	}

	v2, err = u2.LoadFile("file2")
	if err != nil {
		t.Error("Failed to download the file after sharing", err)
		return
	}

	if !reflect.DeepEqual(v, v2) {
		t.Error("Shared file is not the same", v, v2)
		return
	}
	///////////////////

	// alice shares with charlie
	accessToken, err = u.ShareFile("file1", "charlie")
	if err != nil {
		t.Error("Failed to share the a file", err)
		return
	}

	err = u3.ReceiveFile("file3", "alice", accessToken)
	if err != nil {
		t.Error("Failed to receive the share message", err)
		return
	}

	v3, err := u3.LoadFile("file3")
	if err != nil {
		t.Error("Failed to download the file after sharing", err)
		return
	}

	if !reflect.DeepEqual(v, v3) {
		t.Error("Shared file is not the same", v, v3)
		return
	}
	//////////////////

	v, err = u.LoadFile("file1")
	if err != nil {
		t.Error("Failed to download the file from alice after share", err)
		return
	}

	// Alice revokes from Bob
	err = u.RevokeFile("file1", "bob")
	if err != nil {
		t.Error("Failed to revoke access from bob", err)
		return
	}
	////////////

	v, err = u.LoadFile("file1")
	if err != nil {
		t.Error("Failed to download the file from alice after revoke", err)
		return
	}
	v3, err = u3.LoadFile("file3")
	if err != nil {
		t.Error("Failed to download the file from charlie after alice revoked bob", err)
		return
	}

	v2, err = u2.LoadFile("file2")
	if err == nil {
		t.Error("Bob still has access after revocation", err)
		return
	}
}
func TestRevoke_3(t *testing.T) {
	//alice shares with bob, bob shares with charlie, revoke from bob - neither should be able to load
	clear()

	// initalize users
	u, err := InitUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}
	u2, err2 := InitUser("bob", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}
	u3, err3 := InitUser("charlie", "foobar")
	if err3 != nil {
		t.Error("Failed to initialize bob", err3)
		return
	}
	/////////////////

	//alice create file
	v := []byte("This is a test")
	u.StoreFile("file1", v)
	//////////////////

	// alice shares with bob
	accessToken, err := u.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Failed to share the a file", err)
		return
	}

	err = u2.ReceiveFile("file2", "alice", accessToken)
	if err != nil {
		t.Error("Failed to receive the share message", err)
		return
	}
	///////////////////

	// bob shares with charlie
	accessToken, err = u2.ShareFile("file2", "charlie")
	if err != nil {
		t.Error("Failed to share the a file", err)
		return
	}

	err = u3.ReceiveFile("file3", "bob", accessToken)
	if err != nil {
		t.Error("Failed to receive the share message", err)
		return
	}

	v3, err := u3.LoadFile("file3")
	if err != nil {
		t.Error("Failed to download the file after sharing", err)
		return
	}

	if !reflect.DeepEqual(v, v3) {
		t.Error("Shared file is not the same", v, v3)
		return
	}
	//////////////////

	v, err = u.LoadFile("file1")
	if err != nil {
		t.Error("Failed to download the file from alice after share", err)
		return
	}

	// Alice revokes from Bob
	err = u.RevokeFile("file1", "bob")
	if err != nil {
		t.Error("Failed to revoke access from bob", err)
		return
	}
	////////////

	v, err = u.LoadFile("file1")
	if err != nil {
		t.Error("Failed to download the file from alice after revoke", err)
		return
	}
	v3, err = u3.LoadFile("file3")
	if err == nil {
		t.Error("Charlie still has access after revocation", err)
		return
	}

	_, err = u2.LoadFile("file2")
	if err == nil {
		t.Error("Bob still has access after revocation", err)
		return
	}
}

func TestRevoke_4(t *testing.T) {
	// test error check: share when user does not have acces to file
	clear()

	// initalize users
	u, err := InitUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}
	u2, err2 := InitUser("bob", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}
	u3, err3 := InitUser("charlie", "foobar")
	if err3 != nil {
		t.Error("Failed to initialize bob", err3)
		return
	}
	/////////////////

	//alice create file
	v := []byte("This is a test")
	u.StoreFile("file1", v)
	//////////////////

	// bob shares with charlie
	_, err = u2.ShareFile("file1", "charlie")
	if err == nil {
		t.Error("Failed to recognize that Bob does not have access to file and cannot share the file", err)
		return
	}

	// Alice revokes from Bob w/o sharing with Bob
	err = u.RevokeFile("file1", "bob")
	if err == nil {
		t.Error("Failed to recognize alice cannot revoke from bob", err)
		return
	}
	////////////

	// test error check: alice share Bob, bob share charlie, but he cannot revoke charlie
	accessToken, err := u.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Failed to share the file", err)
		return
	}

	err = u2.ReceiveFile("file2", "alice", accessToken)
	if err != nil {
		t.Error("Failed to receive the share message", err)
		return
	}

	accessToken, err = u2.ShareFile("file2", "charlie")
	if err != nil {
		t.Error("Failed to allow participant (not owner) to share the file", err)
		return
	}

	err = u3.ReceiveFile("file3", "bob", accessToken)
	if err != nil {
		t.Error("Failed to receive the share message", err)
		return
	}

	err = u2.RevokeFile("file1", "charlie")
	if err == nil {
		t.Error("Failed to recognize bob (who is not the owner) cannot revoke from charlie", err)
		return
	}

}

func TestRevoke_5(t *testing.T) {
	clear()

	// initalize users
	u, err := InitUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}
	u2, err2 := InitUser("bob", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}
	/////////////////

	//alice create file
	v := []byte("This is a test")
	u.StoreFile("file1", v)
	//////////////////

	// alice shares with bob
	accessToken, err := u.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Failed to share the a file", err)
		return
	}

	err = u2.ReceiveFile("file2", "alice", accessToken)
	if err != nil {
		t.Error("Failed to receive the share message", err)
		return
	}

	//alice revokes from bob
	err = u.RevokeFile("file1", "bob")
	if err != nil {
		t.Error("Failed to revoke from bob", err)
		return
	}

	//bob attempts to load
	_, err = u2.LoadFile("file2")
	if err == nil {
		t.Error("Failed to correctly revoke from Bob.", err)
		return
	}

	//bob attempts to receive
	err = u2.ReceiveFile("file2", "alice", accessToken)
	if err == nil {
		t.Error("Bob was able to receive after being revoked", err)
		return
	}

	//bob tries to append
	err = u2.AppendFile("file2", []byte("this should not be appended"))
	if err == nil {
		t.Error("Bob was able to append after being revoked", err)
		return
	}

	//alice loads to make sure bob didn't append
	alice_v, err := u.LoadFile("file1")
	if err != nil {
		t.Error("Alice failed to correctly load.", err)
		return
	}

	if !reflect.DeepEqual(v, alice_v) {
		t.Error("Shared file is not the same", v, alice_v)
		return
	}

	//bob attempts to share
	_, err3 := InitUser("charlie", "foobar")
	if err3 != nil {
		t.Error("Failed to initialize charlie", err3)
		return
	}

	accessToken, err = u2.ShareFile("file2", "charlie")
	if err == nil {
		t.Error("Bob was able to share after being revoked", err)
		return
	}

	//bob attempts to revoke
	err = u2.RevokeFile("file2", "alice")
	if err == nil {
		t.Error("Bob was able to revoke from alice after being revoked", err)
		return
	}

	bob_new_v := []byte("Bob's file")
	err = u2.StoreFile("file2", bob_new_v)
	if err == nil {
		t.Error("Bob was able to overwrite after being revoked", err)
		return
	}

}

func TestShareReceiveOrder(t *testing.T) {
	clear()

	// initalize users
	u, err := InitUser("alice", "<PASSWORD>")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}
	u2, err2 := InitUser("bob", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}
	/////////////////

	//alice create file
	v := []byte("This is a test")
	u.StoreFile("file1", v)
	//////////////////

	// alice shares with bob
	accessToken, err := u.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Failed to share the a file", err)
		return
	}

	err = u2.ReceiveFile("file2", "alice", accessToken)
	if err != nil {
		t.Error("Failed to receive the share message", err)
		return
	}

	//bob tries to receive again
	err = u2.ReceiveFile("file2", "alice", accessToken)
	if err == nil {
		t.Error("Bob was able to receive twice", err)
		return
	}

	//bob tries to receive same file under a different name
	err = u2.ReceiveFile("file4", "alice", accessToken)
	if err != nil {
		t.Error("Bob was not able to same file under different name", err)
		return
	}

	//alice tries to receive her own file
	err = u.ReceiveFile("file1", "alice", accessToken)
	if err == nil {
		t.Error("Alice was able to receive her own file under same name", err)
		return
	}

	err = u.ReceiveFile("file2", "alice", accessToken)
	if err == nil {
		t.Error("Alice was able to receive her own file under different name", err)
		return
	}

	err = u.ReceiveFile("file3", "bob", accessToken)
	if err == nil {
		t.Error("Alice was able to receive her own file from bob as sender", err)
		return
	}

	//Charlie tries to receive accessToken intended for bob
	u3, err3 := InitUser("charlie", "foobar")
	if err3 != nil {
		t.Error("Failed to initialize charlie", err3)
		return
	}
	err = u3.ReceiveFile("file3", "alice", accessToken)
	if err == nil {
		t.Error("Charlie was able to receive intended for Bob.", err)
		return
	}

	//bob tries to share with alice
	accessToken, err = u2.ShareFile("file2", "alice")
	if err == nil {
		t.Error("Bob was able to share alice's file with alice", err)
		return
	}

}

func TestRevokeShare(t *testing.T) {
	// test error check: share, revoke, reshare
	clear()
	// initalize users
	u, err := InitUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}
	u2, err2 := InitUser("bob", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}
	/////////////////

	//alice create file
	v := []byte("This is a test")
	u.StoreFile("file1", v)
	//////////////////

	// alice shares with bob
	accessToken, err := u.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Failed to share the a file", err)
		return
	}

	err = u2.ReceiveFile("file2", "alice", accessToken)
	if err != nil {
		t.Error("Failed to receive the share message", err)
		return
	}

	bob_v, err := u2.LoadFile("file2")
	if err != nil {
		t.Error("Bob failed to load after receiving from Alice", err)
		return
	}

	if !reflect.DeepEqual(v, bob_v) {
		t.Error("Shared file is not the same", v, bob_v)
		return
	}

	///////////////////

	// Alice revokes from Bob
	err = u.RevokeFile("file1", "bob")
	if err != nil {
		t.Error("Failed to revoke access from bob", err)
		return
	}

	bob_v, err = u2.LoadFile("file2")
	if err == nil {
		t.Error("Failed to correctly revoke from Bob.", err)
		return
	}

	////////////

	// alice shares with bob
	accessToken, err = u.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Failed to share the a file", err)
		return
	}

	err = u2.ReceiveFile("file2", "alice", accessToken)
	if err != nil {
		t.Error("Failed to receive the share message", err)
		return
	}

	bob_v, err = u2.LoadFile("file2")
	if err != nil {
		t.Error("Failed to reshare to Bob.", err)
		return
	}
	///////////////////

}

func TestRevokeShare_2(t *testing.T) {
	// test error check: share, revoke, reshare
	clear()
	// initalize users
	u, err := InitUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}
	u2, err2 := InitUser("bob", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}
	u3, err3 := InitUser("charlie", "foobar")
	if err3 != nil {
		t.Error("Failed to initialize bob", err3)
		return
	}
	/////////////////

	//alice create file
	v := []byte("This is a test")
	u.StoreFile("file1", v)
	//////////////////

	// alice shares with bob
	accessToken, err := u.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Failed to share the a file", err)
		return
	}

	err = u2.ReceiveFile("file1", "alice", accessToken)
	if err != nil {
		t.Error("Failed to receive the share message", err)
		return
	}

	// alice shares with charlie
	accessToken, err = u.ShareFile("file1", "charlie")
	if err != nil {
		t.Error("Failed to share the a file", err)
		return
	}

	err = u3.ReceiveFile("file1", "alice", accessToken)
	if err != nil {
		t.Error("Failed to receive the share message", err)
		return
	}

	charlie_v, err := u3.LoadFile("file1")
	if err != nil {
		t.Error("Charlie failed to load after receiving from Alice", err)
		return
	}

	if !reflect.DeepEqual(v, charlie_v) {
		t.Error("Shared file is not the same", v, charlie_v)
		return
	}

	///////////////////

	// Alice revokes from Bob
	err = u.RevokeFile("file1", "bob")
	if err != nil {
		t.Error("Failed to revoke access from bob", err)
		return
	}

	_, err = u2.LoadFile("file1")
	if err == nil {
		t.Error("Failed to correctly revoke from Bob.", err)
		return
	}

	////////////

	// charlie shares with bob
	accessToken, err = u3.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Failed to share the a file", err)
		return
	}

	err = u2.ReceiveFile("file1", "charlie", accessToken)
	if err != nil {
		t.Error("Failed to receive the share message", err)
		return
	}

	bob_v, err := u2.LoadFile("file1")
	if err != nil {
		t.Error("Failed to reshare to Bob.", err)
		return
	}

	if !reflect.DeepEqual(v, bob_v) {
		t.Error("Shared file is not the same", v, bob_v)
		return
	}
	///////////////////
}

func TestRevokeAppend(t *testing.T) {
	// test error check: share, revoke, reshare
	clear()
	// initalize users
	u, err := InitUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}
	u2, err2 := InitUser("bob", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}
	/////////////////

	//alice create file
	v := []byte("This is a test")
	u.StoreFile("file1", v)
	//////////////////

	// alice shares with bob
	accessToken, err := u.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Failed to share the a file", err)
		return
	}

	err = u2.ReceiveFile("file2", "alice", accessToken)
	if err != nil {
		t.Error("Failed to receive the share message", err)
		return
	}

	// Bob append
	err = u2.AppendFile("file2", []byte("Appending to file."))
	if err != nil {
		t.Error("Bob failed to append", err)
	}

	// Alice revokes from Bob
	err = u.RevokeFile("file1", "bob")
	if err != nil {
		t.Error("Failed to revoke access from bob", err)
		return
	}

	_, err = u2.LoadFile("file2")
	if err == nil {
		t.Error("Failed to correctly revoke from Bob.", err)
		return
	}

	////////////

	// Alice load and the appended data should still be there
	v1, err := u.LoadFile("file1")
	if err != nil {
		t.Error("Failed to correctly load after revoking Bob.", err)
		return
	}

	expected_v := []byte("This is a testAppending to file.")
	if !reflect.DeepEqual(expected_v, v1) {
		t.Error("Shared file is not the same", expected_v, v1)
		return
	}
}

func TestRevokeStore(t *testing.T) {
	// test error check: share, revoke, reshare
	clear()
	// initalize users
	u, err := InitUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}
	u2, err2 := InitUser("bob", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}
	/////////////////

	//alice create file
	v := []byte("This is a test")
	u.StoreFile("file1", v)
	//////////////////

	// alice shares with bob
	accessToken, err := u.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Failed to share the a file", err)
		return
	}

	err = u2.ReceiveFile("file2", "alice", accessToken)
	if err != nil {
		t.Error("Failed to receive the share message", err)
		return
	}

	// Bob append
	err = u2.AppendFile("file2", []byte("Appending to file."))
	if err != nil {
		t.Error("Bob failed to append", err)
	}

	// Alice revokes from Bob
	err = u.RevokeFile("file1", "bob")
	if err != nil {
		t.Error("Failed to revoke access from bob", err)
		return
	}

	_, err = u2.LoadFile("file2")
	if err == nil {
		t.Error("Failed to correctly revoke from Bob.", err)
		return
	}

	////////////

	err = u2.StoreFile("file2", []byte("Bob trying to overwrite without access"))
	if err == nil {
		t.Error("Failed to correctly revoke from Bob. He's still storing!", err)
		return
	}
}

func TestRevokeMultChildren(t *testing.T) {
	clear()
	// initalize users
	u, err := InitUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}
	u2, err2 := InitUser("bob", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}
	u3, err := InitUser("charlie", "fubar")
	if err != nil {
		t.Error("Failed to initialize charlie", err)
		return
	}
	u4, err2 := InitUser("david", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize david", err2)
		return
	}
	u5, err := InitUser("eric", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}
	u6, err2 := InitUser("fred", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}

	u7, err2 := InitUser("greg", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}

	//alice create file
	v := []byte("This is a test")
	u.StoreFile("file1", v)
	//////////////////

	//alice shares with bob & charlie
	// alice shares with bob
	accessToken, err := u.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Failed to share the file with bob", err)
		return
	}

	err = u2.ReceiveFile("file2", "alice", accessToken)
	if err != nil {
		t.Error("Bob failed to receive the share message", err)
		return
	}

	accessToken, err = u.ShareFile("file1", "charlie")
	if err != nil {
		t.Error("Failed to share the file with charlie", err)
		return
	}

	err = u3.ReceiveFile("file2", "alice", accessToken)
	if err != nil {
		t.Error("Charlie failed to receive the share message", err)
		return
	}

	//Bob shares with greg
	accessToken, err = u2.ShareFile("file2", "greg")
	if err != nil {
		t.Error("Bob failed to share the file with greg", err)
		return
	}

	err = u7.ReceiveFile("file1", "bob", accessToken)
	if err != nil {
		t.Error("Greg failed to receive the share message", err)
		return
	}

	//Charlie shares with david & eric
	accessToken, err = u3.ShareFile("file2", "david")
	if err != nil {
		t.Error("Charlie failed to share the file with david", err)
		return
	}

	err = u4.ReceiveFile("file1", "charlie", accessToken)
	if err != nil {
		t.Error("David failed to receive the share message", err)
		return
	}

	accessToken, err = u3.ShareFile("file2", "eric")
	if err != nil {
		t.Error("Charlie failed to share the file with eric", err)
		return
	}

	err = u5.ReceiveFile("file1", "charlie", accessToken)
	if err != nil {
		t.Error("Eric failed to receive the share message", err)
		return
	}

	//Eric shares with fred
	accessToken, err = u5.ShareFile("file1", "fred")
	if err != nil {
		t.Error("Eric failed to share the file with eric", err)
		return
	}

	err = u6.ReceiveFile("file1", "eric", accessToken)
	if err != nil {
		t.Error("Fred failed to receive the share message", err)
		return
	}

	//Alice revokes from charlie
	err = u.RevokeFile("file1", "charlie")
	if err != nil {
		t.Error("Alice failed to revoke from charlie", err)
		return
	}

	//Check that only alice, bob, greg can load
	_, err = u.LoadFile("file1")
	if err != nil {
		t.Error("Alice failed to load", err)
		return
	}

	_, err = u2.LoadFile("file2")
	if err != nil {
		t.Error("Bob failed to load", err)
		return
	}

	_, err = u3.LoadFile("file2")
	if err == nil {
		t.Error("Charlie still has access", err)
		return
	}

	_, err = u4.LoadFile("file1")
	if err == nil {
		t.Error("David still has access", err)
		return
	}

	_, err = u5.LoadFile("file1")
	if err == nil {
		t.Error("Eric still has access", err)
		return
	}

	_, err = u6.LoadFile("file1")
	if err == nil {
		t.Error("Fred still has access", err)
		return
	}

	_, err = u7.LoadFile("file1")
	if err != nil {
		t.Error("Greg failed to load", err)
		return
	}

}

func TestShareALot(t *testing.T) {
	clear()
	// initalize users
	u, err := InitUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}
	u2, err2 := InitUser("bob", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}
	u3, err := InitUser("charlie", "fubar")
	if err != nil {
		t.Error("Failed to initialize charlie", err)
		return
	}
	u4, err2 := InitUser("david", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize david", err2)
		return
	}
	u5, err := InitUser("eric", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}
	u6, err2 := InitUser("fred", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}

	u7, err2 := InitUser("greg", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}

	u8, err2 := InitUser("harry", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize harry", err2)
		return
	}

	u9, err2 := InitUser("izzy", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize izzy", err2)
		return
	}

	u10, err2 := InitUser("john", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize john", err2)
		return
	}

	u11, err2 := InitUser("kevin", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize kevin", err2)
		return
	}

	u12, err2 := InitUser("lisa", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize lisa", err2)
		return
	}

	u13, err2 := InitUser("monica", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize monica", err2)
		return
	}

	u14, err2 := InitUser("nancy", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize nancy", err2)
		return
	}

	u15, err2 := InitUser("olaf", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize olaf", err2)
		return
	}

	u16, err2 := InitUser("pat", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize pat", err2)
		return
	}

	//alice create file
	v := []byte("This is a test")
	u.StoreFile("file1", v)
	//////////////////

	//alice shares with bob & charlie
	// alice shares with bob
	accessToken, err := u.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Failed to share the file with bob", err)
		return
	}

	err = u2.ReceiveFile("file2", "alice", accessToken)
	if err != nil {
		t.Error("Bob failed to receive the share message", err)
		return
	}

	accessToken, err = u.ShareFile("file1", "charlie")
	if err != nil {
		t.Error("Failed to share the file with charlie", err)
		return
	}

	err = u3.ReceiveFile("file2", "alice", accessToken)
	if err != nil {
		t.Error("Charlie failed to receive the share message", err)
		return
	}

	//Bob shares with greg
	accessToken, err = u2.ShareFile("file2", "greg")
	if err != nil {
		t.Error("Bob failed to share the file with greg", err)
		return
	}

	err = u7.ReceiveFile("file1", "bob", accessToken)
	if err != nil {
		t.Error("Greg failed to receive the share message", err)
		return
	}

	//Charlie shares with david & eric
	accessToken, err = u3.ShareFile("file2", "david")
	if err != nil {
		t.Error("Charlie failed to share the file with david", err)
		return
	}

	err = u4.ReceiveFile("file1", "charlie", accessToken)
	if err != nil {
		t.Error("David failed to receive the share message", err)
		return
	}

	accessToken, err = u3.ShareFile("file2", "eric")
	if err != nil {
		t.Error("Charlie failed to share the file with eric", err)
		return
	}

	err = u5.ReceiveFile("file1", "charlie", accessToken)
	if err != nil {
		t.Error("Eric failed to receive the share message", err)
		return
	}

	//Eric shares with fred
	accessToken, err = u5.ShareFile("file1", "fred")
	if err != nil {
		t.Error("Eric failed to share the file with eric", err)
		return
	}

	err = u6.ReceiveFile("file1", "eric", accessToken)
	if err != nil {
		t.Error("Fred failed to receive the share message", err)
		return
	}

	accessToken, err = u5.ShareFile("file1", "harry")
	if err != nil {
		t.Error("Eric failed to share the file with eric", err)
		return
	}

	err = u8.ReceiveFile("file1", "eric", accessToken)
	if err != nil {
		t.Error("harry failed to receive the share message", err)
		return
	}

	accessToken, err = u5.ShareFile("file1", "izzy")
	if err != nil {
		t.Error("Eric failed to share the file with eric", err)
		return
	}

	err = u9.ReceiveFile("file1", "eric", accessToken)
	if err != nil {
		t.Error("izzy failed to receive the share message", err)
		return
	}

	accessToken, err = u5.ShareFile("file1", "john")
	if err != nil {
		t.Error("Eric failed to share the file with eric", err)
		return
	}

	err = u10.ReceiveFile("file1", "eric", accessToken)
	if err != nil {
		t.Error("john failed to receive the share message", err)
		return
	}

	accessToken, err = u5.ShareFile("file1", "kevin")
	if err != nil {
		t.Error("Eric failed to share the file with eric", err)
		return
	}

	err = u11.ReceiveFile("file1", "eric", accessToken)
	if err != nil {
		t.Error("kevin failed to receive the share message", err)
		return
	}

	accessToken, err = u5.ShareFile("file1", "lisa")
	if err != nil {
		t.Error("Eric failed to share the file with eric", err)
		return
	}

	err = u12.ReceiveFile("file1", "eric", accessToken)
	if err != nil {
		t.Error("lisa failed to receive the share message", err)
		return
	}

	accessToken, err = u5.ShareFile("file1", "monica")
	if err != nil {
		t.Error("Eric failed to share the file with eric", err)
		return
	}

	err = u13.ReceiveFile("file1", "eric", accessToken)
	if err != nil {
		t.Error("monica failed to receive the share message", err)
		return
	}

	accessToken, err = u5.ShareFile("file1", "nancy")
	if err != nil {
		t.Error("Eric failed to share the file with eric", err)
		return
	}

	err = u14.ReceiveFile("file1", "eric", accessToken)
	if err != nil {
		t.Error("nancy failed to receive the share message", err)
		return
	}

	accessToken, err = u5.ShareFile("file1", "olaf")
	if err != nil {
		t.Error("Eric failed to share the file with eric", err)
		return
	}

	err = u15.ReceiveFile("file1", "eric", accessToken)
	if err != nil {
		t.Error("olaf failed to receive the share message", err)
		return
	}

	accessToken, err = u5.ShareFile("file1", "pat")
	if err != nil {
		t.Error("Eric failed to share the file with eric", err)
		return
	}

	err = u16.ReceiveFile("file1", "eric", accessToken)
	if err != nil {
		t.Error("pat failed to receive the share message", err)
		return
	}

}

func TestShareTreeSearch(t *testing.T) {
	clear()
	// initalize users
	u, err := InitUser("alice", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}
	u2, err2 := InitUser("bob", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}
	u3, err := InitUser("charlie", "fubar")
	if err != nil {
		t.Error("Failed to initialize charlie", err)
		return
	}
	u4, err2 := InitUser("david", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize david", err2)
		return
	}
	u5, err := InitUser("eric", "fubar")
	if err != nil {
		t.Error("Failed to initialize user", err)
		return
	}
	u6, err2 := InitUser("fred", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}

	u7, err2 := InitUser("greg", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}

	u8, err2 := InitUser("harry", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize harry", err2)
		return
	}

	u9, err2 := InitUser("izzy", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize izzy", err2)
		return
	}

	u10, err2 := InitUser("john", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize john", err2)
		return
	}

	_, err2 = InitUser("kevin", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize kevin", err2)
		return
	}

	//alice create file
	v := []byte("This is a test")
	u.StoreFile("file1", v)
	//////////////////

	//alice shares with bob & charlie
	// alice shares with bob
	accessToken, err := u.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Failed to share the file with bob", err)
		return
	}

	err = u2.ReceiveFile("file1", "alice", accessToken)
	if err != nil {
		t.Error("Bob failed to receive the share message", err)
		return
	}

	accessToken, err = u2.ShareFile("file1", "charlie")
	if err != nil {
		t.Error("Failed to share the file with charlie", err)
		return
	}

	err = u3.ReceiveFile("file1", "bob", accessToken)
	if err != nil {
		t.Error("Charlie failed to receive the share message", err)
		return
	}

	//Bob shares with greg
	accessToken, err = u3.ShareFile("file1", "david")
	if err != nil {
		t.Error("Bob failed to share the file with greg", err)
		return
	}

	err = u4.ReceiveFile("file1", "charlie", accessToken)
	if err != nil {
		t.Error("Greg failed to receive the share message", err)
		return
	}

	accessToken, err = u4.ShareFile("file1", "eric")
	if err != nil {
		t.Error("Charlie failed to share the file with david", err)
		return
	}

	err = u5.ReceiveFile("file1", "david", accessToken)
	if err != nil {
		t.Error("David failed to receive the share message", err)
		return
	}

	accessToken, err = u5.ShareFile("file1", "fred")
	if err != nil {
		t.Error("Charlie failed to share the file with eric", err)
		return
	}

	err = u6.ReceiveFile("file1", "eric", accessToken)
	if err != nil {
		t.Error("Eric failed to receive the share message", err)
		return
	}

	accessToken, err = u6.ShareFile("file1", "greg")
	if err != nil {
		t.Error("Eric failed to share the file with eric", err)
		return
	}

	err = u7.ReceiveFile("file1", "fred", accessToken)
	if err != nil {
		t.Error("Fred failed to receive the share message", err)
		return
	}

	accessToken, err = u7.ShareFile("file1", "harry")
	if err != nil {
		t.Error("Eric failed to share the file with eric", err)
		return
	}

	err = u8.ReceiveFile("file1", "greg", accessToken)
	if err != nil {
		t.Error("harry failed to receive the share message", err)
		return
	}

	accessToken, err = u8.ShareFile("file1", "izzy")
	if err != nil {
		t.Error("Eric failed to share the file with eric", err)
		return
	}

	err = u9.ReceiveFile("file1", "harry", accessToken)
	if err != nil {
		t.Error("izzy failed to receive the share message", err)
		return
	}

	accessToken, err = u9.ShareFile("file1", "john")
	if err != nil {
		t.Error("Eric failed to share the file with eric", err)
		return
	}

	err = u10.ReceiveFile("file1", "izzy", accessToken)
	if err != nil {
		t.Error("john failed to receive the share message", err)
		return
	}

	err = u.RevokeFile("file1", "john")
	if err != nil {
		t.Error("Failed to revoke from john", err)
		return
	}

	err = u.RevokeFile("file1", "kevin")
	if err == nil {
		t.Error("Should have errored")
		return
	}
}

func TestRetrieveAccessTokenError(t *testing.T) {
	clear()
	u, err := InitUser("alice", "foobar")
	if err != nil {
		t.Error("Failed to initialize bob", err)
		return
	}

	u2, err2 := InitUser("bob", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}

	//alice share with bob
	v := []byte("Alice's file")
	err = u.StoreFile("file1", v)
	if err != nil {
		t.Error("Failed to store", err)
		return
	}

	accessToken, _ := u.ShareFile("file1", "bob")

	//bob receive accessToken
	u2.ReceiveFile("file1", "alice", accessToken)

	//delete the accessToken from datastore
	userlib.DatastoreDelete(accessToken)

	//expect error when bob tries to load
	_, err = u2.LoadFile("file1")
	if err == nil {
		t.Error("Did not recognize accessToken is missing from datastores", err)
		return
	}
}

func TestAppendError(t *testing.T) {
	clear()
	u, err := InitUser("alice", "foobar")
	if err != nil {
		t.Error("Failed to initialize alice", err)
		return
	}

	v := []byte("Alice's file")
	err = u.StoreFile("file1", v)
	if err != nil {
		t.Error("Failed to store", err)
		return
	}

	err = u.AppendFile("file1", []byte(""))
	if err == nil {
		t.Error("Failed to recognize no bytes to append", err)
		return
	}

	u2, err := InitUser("bob", "foobar")
	if err != nil {
		t.Error("Failed to initialize bob", err)
		return
	}

	err = u2.AppendFile("file1", []byte("bob can't do this"))
	if err == nil {
		t.Error("Failed to recognize bob can't append", err)
		return
	}

	//Alice appends a bunch of stuff serially
	u.AppendFile("file1", []byte("Append1"))
	u.AppendFile("file1", []byte("Append2"))
	u.AppendFile("file1", []byte("Append3"))
	u.AppendFile("file1", []byte("Append4"))
	u.AppendFile("file1", []byte("Append5"))
	u.AppendFile("file1", []byte("Append6"))
	u.AppendFile("file1", []byte("Append7"))
	u.AppendFile("file1", []byte("Append8"))
	u.AppendFile("file1", []byte("Append9"))
	u.AppendFile("file1", []byte("Append10"))
	u.AppendFile("file1", []byte("Append11"))
	u.AppendFile("file1", []byte("Append12"))

	v1, err := u.LoadFile("file1")
	if err != nil {
		t.Error("Failed to load after multiple appends", err)
		return
	}
	expected_v := []byte("Alice's fileAppend1Append2Append3Append4Append5Append6" +
		"Append7Append8Append9Append10Append11Append12")

	if !reflect.DeepEqual(expected_v, v1) {
		t.Error("appended file is not correc", expected_v, v1)
		return
	}

	accessToken, err := u.ShareFile("file1", "bob")
	if err != nil {
		t.Error("Alice failed to share the file with bob", err)
		return
	}

	err = u2.ReceiveFile("file1", "alice", accessToken)
	if err != nil {
		t.Error("bob failed to receive the share message", err)
		return
	}

	err = u2.StoreFile("file1", []byte("Overwriting everything"))
	if err != nil {
		t.Error("bob failed to overwrite", err)
		return
	}

	v2, err := u.LoadFile("file1")
	if err != nil {
		t.Error("Alice failed to load after bob overwrite", err)
		return
	}

	expected_v = []byte("Overwriting everything")
	if !reflect.DeepEqual(expected_v, v2) {
		t.Error("overwritten file is not correct", expected_v, v2)
		return
	}

	u2.AppendFile("file1", []byte("Append1"))
	u.AppendFile("file1", []byte("Append2"))
	u2.AppendFile("file1", []byte("Append3"))
	u.AppendFile("file1", []byte("Append4"))
	u2.AppendFile("file1", []byte("Append5"))
	u.AppendFile("file1", []byte("Append6"))
	u2.AppendFile("file1", []byte("Append7"))
	u.AppendFile("file1", []byte("Append8"))
	u2.AppendFile("file1", []byte("Append9"))
	u.AppendFile("file1", []byte("Append10"))
	u2.AppendFile("file1", []byte("Append11"))
	u.AppendFile("file1", []byte("Append12"))

	v2, err = u.LoadFile("file1")
	if err != nil {
		t.Error("Alice failed to load after bob appends a lot", err)
		return
	}
	expected_v = []byte("Overwriting everythingAppend1Append2Append3Append4Append5Append6" +
		"Append7Append8Append9Append10Append11Append12")

	if !reflect.DeepEqual(expected_v, v2) {
		t.Error("appended file is not correct", string(expected_v), string(v2))
		return
	}

}

func TestLoadErrorCorruptedHash(t *testing.T) {
	clear()

	userlib.SetDebugStatus(true)
	u, err := InitUser("alice", "foobar")
	if err != nil {
		t.Error("Failed to initialize alice", err)
		return
	}

	ds := userlib.DatastoreGetMap()
	ds_orig := make(map[uuid.UUID][]byte)
	for k, v := range ds {
		ds_orig[k] = v
	}

	v := []byte("Alice's file")
	err = u.StoreFile("file1", v)
	if err != nil {
		t.Error("Failed to store", err)
		return
	}

	ds = userlib.DatastoreGetMap()
	ds_orig2 := make(map[uuid.UUID][]byte)
	for k, v := range ds {
		ds_orig2[k] = v
	}

	diff := []uuid.UUID{}

	for k, _ := range ds_orig2 {
		if _, ok := ds_orig[k]; !ok {
			diff = append(diff, k)
		}
	}
	var file1HMACuuid uuid.UUID
	file1HMACuuid = uuid.Nil

	for i := 0; i < len(diff); i++ {
		elem := diff[i]
		element, _ := userlib.DatastoreGet(elem)
		if len(element) == 64 {
			file1HMACuuid = elem
		}
	}
	userlib.DatastoreSet(file1HMACuuid, userlib.RandomBytes(64))

	_, err = u.LoadFile("file1")
	if err == nil {
		t.Error("Failed to detect corrupted file struct", err)
		return
	}

}

func TestFuzzDatastore(t *testing.T) {
	clear()

	userlib.SetDebugStatus(true)
	//// Initialize and edit datastore
	u, err := InitUser("alice", "foobar")
	if err != nil {
		t.Error("Failed to initialize alice", err)
		return
	}

	ds := userlib.DatastoreGetMap()
	ds_orig := make(map[uuid.UUID][]byte)
	for k, v := range ds {
		ds_orig[k] = v
		// userlib.DebugMsg(strconv.Itoa(len(v)))
	}

	//////// Get node 1
	v := []byte("Alice's file")
	err = u.StoreFile("file1", v)
	if err != nil {
		t.Error("Failed to store", err)
		return
	}

	ds = userlib.DatastoreGetMap()
	ds_orig2 := make(map[uuid.UUID][]byte)
	for k, v := range ds {
		ds_orig2[k] = v
	}

	diff := []uuid.UUID{}

	for k, _ := range ds_orig2 {
		if _, ok := ds_orig[k]; !ok {
			diff = append(diff, k)
		}
	}

	for i := 0; i < len(diff); i++ {
		elem := diff[i]
		element, _ := userlib.DatastoreGet(elem)

		// corrupt
		userlib.DatastoreSet(elem, []byte("Corrupting elem"))

		// check loadfile fails
		_, err = u.LoadFile("file1")
		if err == nil {
			t.Error("Failed to detect corruption. i = ", i, err)
			return
		}

		//truncate
		length := int(len(element) / 2)
		data := element[:length]
		userlib.DatastoreSet(elem, data)

		// check laodfile fails
		_, err = u.LoadFile("file1")
		if err == nil {
			t.Error("Failed to detect corruption. i = ", i, err)
			return
		}

		//clear
		userlib.DatastoreSet(elem, []byte(""))

		_, err = u.LoadFile("file1")
		if err == nil {
			t.Error("Failed to detect corruption. i = ", i, err)
			return
		}

		//replace original value
		userlib.DatastoreSet(elem, element)
	}
	/////////////////

	err = u.AppendFile("file1", []byte("Appending data 1"))
	if err != nil {
		t.Error("Failed to append 1", err)
		return
	}

	ds = userlib.DatastoreGetMap()
	ds_orig3 := make(map[uuid.UUID][]byte)
	for k, v := range ds {
		ds_orig3[k] = v
	}

	diff = []uuid.UUID{}

	for k, _ := range ds_orig3 {
		if _, ok := ds_orig2[k]; !ok {
			diff = append(diff, k)
		}
	}

	for i := 0; i < len(diff); i++ {
		elem := diff[i]
		element, _ := userlib.DatastoreGet(elem)

		// corrupt
		userlib.DatastoreSet(elem, []byte("Corrupting elem"))

		// check loadfile fails
		_, err = u.LoadFile("file1")
		if err == nil {
			t.Error("Failed to detect corruption. i = ", i, err)
			return
		}

		//truncate
		length := int(len(element) / 2)
		data := element[:length]
		userlib.DatastoreSet(elem, data)

		// check laodfile fails
		_, err = u.LoadFile("file1")
		if err == nil {
			t.Error("Failed to detect corruption. i = ", i, err)
			return
		}

		//clear
		userlib.DatastoreSet(elem, []byte(""))

		_, err = u.LoadFile("file1")
		if err == nil {
			t.Error("Failed to detect corruption. i = ", i, err)
			return
		}

		//replace original value
		userlib.DatastoreSet(elem, element)
	}
	///////////////

	err = u.AppendFile("file1", []byte("Appending data 2"))
	if err != nil {
		t.Error("Failed to append 2", err)
		return
	}

	ds = userlib.DatastoreGetMap()
	ds_orig4 := make(map[uuid.UUID][]byte)
	for k, v := range ds {
		ds_orig4[k] = v
	}

	diff = []uuid.UUID{}

	for k, _ := range ds_orig4 {
		if _, ok := ds_orig3[k]; !ok {
			diff = append(diff, k)
		}
	}

	for i := 0; i < len(diff); i++ {
		elem := diff[i]
		element, _ := userlib.DatastoreGet(elem)

		// corrupt
		userlib.DatastoreSet(elem, []byte("Corrupting elem"))

		// check loadfile fails
		_, err = u.LoadFile("file1")
		if err == nil {
			t.Error("Failed to detect corruption. i = ", i, err)
			return
		}

		//truncate
		length := int(len(element) / 2)
		data := element[:length]
		userlib.DatastoreSet(elem, data)

		// check laodfile fails
		_, err = u.LoadFile("file1")
		if err == nil {
			t.Error("Failed to detect corruption. i = ", i, err)
			return
		}

		//clear
		userlib.DatastoreSet(elem, []byte(""))

		_, err = u.LoadFile("file1")
		if err == nil {
			t.Error("Failed to detect corruption. i = ", i, err)
			return
		}

		//replace original value
		userlib.DatastoreSet(elem, element)
	}

	u2, err2 := InitUser("bob", "fubar")
	if err2 != nil {
		t.Error("Failed to initialize alice", err2)
		return
	}

	accessToken, err2 := u.ShareFile("file1", "bob")
	if err2 != nil {
		t.Error("Failed to share with bob", err2)
		return
	}

	ds = userlib.DatastoreGetMap()
	ds_orig5 := make(map[uuid.UUID][]byte)
	for k, v := range ds {
		ds_orig4[k] = v
	}

	diff = []uuid.UUID{}

	for k, _ := range ds_orig5 {
		if _, ok := ds_orig4[k]; !ok {
			diff = append(diff, k)
		}
	}

	for i := 0; i < len(diff); i++ {
		elem := diff[i]
		element, _ := userlib.DatastoreGet(elem)

		// corrupt
		userlib.DatastoreSet(elem, []byte("Corrupting elem"))

		// check receivefile fails
		err2 = u2.ReceiveFile("file1", "alice", accessToken)
		if err2 == nil {
			t.Error("Failed to receive from alice", err2)
			return
		}

		//truncate
		length := int(len(element) / 2)
		data := element[:length]
		userlib.DatastoreSet(elem, data)

		// check laodfile fails
		err2 = u2.ReceiveFile("file1", "alice", accessToken)
		if err2 == nil {
			t.Error("Failed to receive from alice", err2)
			return
		}

		//clear
		userlib.DatastoreSet(elem, []byte(""))

		// check laodfile fails
		err2 = u2.ReceiveFile("file1", "alice", accessToken)
		if err2 == nil {
			t.Error("Failed to receive from alice", err2)
			return
		}

		//replace original value
		userlib.DatastoreSet(elem, element)
	}
}

func TestSwapDatastore(t *testing.T) {
	clear()

	userlib.SetDebugStatus(true)
	//// Initialize and edit datastore
	u, err := InitUser("alice", "foobar")
	if err != nil {
		t.Error("Failed to initialize alice", err)
		return
	}

	ds := userlib.DatastoreGetMap()
	ds_orig := make(map[uuid.UUID][]byte)
	for k, v := range ds {
		ds_orig[k] = v
	}

	//////// Get node 1
	v := []byte("Alice's file")
	err = u.StoreFile("file1", v)
	if err != nil {
		t.Error("Failed to store", err)
		return
	}

	ds = userlib.DatastoreGetMap()
	ds_orig2 := make(map[uuid.UUID][]byte)
	for k, v := range ds {
		ds_orig2[k] = v
	}

	diff := []uuid.UUID{}

	for k, _ := range ds_orig2 {
		if _, ok := ds_orig[k]; !ok {
			diff = append(diff, k)
		}
	}

	for i := 0; i < len(diff)-1; i += 1 {
		elem1 := diff[i]
		element1, _ := userlib.DatastoreGet(elem1)
		elem2 := diff[i+1]
		element2, _ := userlib.DatastoreGet(elem2)

		userlib.DatastoreSet(elem1, element2)
		userlib.DatastoreSet(elem2, element1)

		_, err = u.LoadFile("file1")
		if err == nil {
			t.Error("Failed to recognize datastore swap", err)
			return
		}

		userlib.DatastoreSet(elem1, element1)
		userlib.DatastoreSet(elem2, element2)
	}
}

// initialize alice and bob
// create file --> obtain diff which will have file related stuff
// corrupt, share, revoke error in a for loop

func TestRevokeDataErrors(t *testing.T) {
	clear()

	userlib.SetDebugStatus(true)
	//// Initialize and edit datastore
	u, err := InitUser("alice", "foobar")
	if err != nil {
		t.Error("Failed to initialize alice", err)
		return
	}

	u2, err2 := InitUser("bob", "foobar")
	if err2 != nil {
		t.Error("Failed to initialize bob", err2)
		return
	}

	ds := userlib.DatastoreGetMap()
	ds_orig := make(map[uuid.UUID][]byte)
	for k, v := range ds {
		ds_orig[k] = v
		// userlib.DebugMsg(strconv.Itoa(len(v)))
	}

	//////// Get node 1
	v := []byte("Alice's file")
	err = u.StoreFile("file1", v)
	if err != nil {
		t.Error("Failed to store", err)
		return
	}

	u.AppendFile("file1", []byte("More data"))

	ds = userlib.DatastoreGetMap()
	ds_orig2 := make(map[uuid.UUID][]byte)
	for k, v := range ds {
		ds_orig2[k] = v
	}

	diff_file := []uuid.UUID{}

	for k, _ := range ds_orig2 {
		if _, ok := ds_orig[k]; !ok {
			diff_file = append(diff_file, k)
		}
	}

	accessToken, _ := u.ShareFile("file1", "bob")
	u2.ReceiveFile("file1", "alice", accessToken)

	for i := 0; i < len(diff_file); i++ {
		elem := diff_file[i]
		element, _ := userlib.DatastoreGet(elem)

		// corrupt
		userlib.DatastoreSet(elem, []byte("Corrupting elem"))

		// check loadfile fails
		err = u.RevokeFile("file1", "bob")
		if err == nil {
			t.Error("Failed to detect corruption. i = ", i, err)
			return
		}

		//truncate
		length := int(len(element) / 2)
		data := element[:length]
		userlib.DatastoreSet(elem, data)

		// check laodfile fails
		err = u.RevokeFile("file1", "bob")
		if err == nil {
			t.Error("Failed to detect corruption. i = ", i, err)
			return
		}

		//clear
		userlib.DatastoreSet(elem, []byte(""))

		err = u.RevokeFile("file1", "bob")
		if err == nil {
			t.Error("Failed to detect corruption. i = ", i, err)
			return
		}

		//replace original value
		userlib.DatastoreSet(elem, element)
	}
}

func TestAppendEfficiency(t *testing.T) {
	clear()

	userlib.SetDebugStatus(true)
	//// Initialize and edit datastore
	u, err := InitUser("alice", "foobar")
	if err != nil {
		t.Error("Failed to initialize alice", err)
		return
	}

	v := []byte("Alice's file")
	err = u.StoreFile("file1", v)
	if err != nil {
		t.Error("Failed to store", err)
		return
	}

	v1 := []byte("Alice's fileAlice's fileAlice's fileAlice's fileAlice's fileAlice's fileAlice's fileAlice's fileAlice's fileAlice's fileAlice's file")
	err = u.StoreFile("file2", v1)
	if err != nil {
		t.Error("Failed to store", err)
		return
	}

	//Check that append doesn't scale with size of file
	userlib.DatastoreResetBandwidth()
	u.AppendFile("file1", []byte("More data."))

	b1 := userlib.DatastoreGetBandwidth()

	userlib.DatastoreResetBandwidth()
	u.AppendFile("file2", []byte("More data."))

	b2 := userlib.DatastoreGetBandwidth()
	difference := b1 - b2

	if difference < 0 {
		if -1*difference > 50 {
			t.Error("Not an efficient append", b1, b2)
			return
		}
	} else {
		if difference > 50 {
			t.Error("Not an efficient append", difference)
			return
		}
	}

	// Check that append doesn't scale with number of appends
	userlib.DatastoreResetBandwidth()
	u.StoreFile("file1", []byte("Orig data"))

	for i := 0; i < 50; i++ {
		u.AppendFile("file1", []byte("append"))
	}

	b1 = userlib.DatastoreGetBandwidth()
	userlib.DatastoreResetBandwidth()
	for i := 50; i < 100; i++ {
		u.AppendFile("file1", []byte("append"))
	}

	b2 = userlib.DatastoreGetBandwidth()
	difference = b1 - b2

	if difference < 0 {
		if -1*difference > 5000 {
			t.Error("Not an efficient append num appends", b1, b2)
			return
		}
	} else {
		if difference > 5000 {
			t.Error("Not an efficient append num appends", b1, b2)
			return
		}
	}

	//AppendFile cannot scale with the number of previous appends (from piazza)
	u.StoreFile("file1", []byte("A"))
	u.StoreFile("file2", []byte("A"))

	for i := 0; i < 50; i++ {
		u.AppendFile("file1", []byte("append"))
	}
	userlib.DatastoreResetBandwidth()
	u.AppendFile("file1", []byte("B"))
	b1 = userlib.DatastoreGetBandwidth()
	userlib.DatastoreResetBandwidth()
	u.AppendFile("file2", []byte("B"))
	b2 = userlib.DatastoreGetBandwidth()

	difference = b1 - b2
	if difference < 0 {
		if -1*difference > 50 {
			t.Error("Not an efficient append prev appends", b1, b2)
			return
		}
	} else {
		if difference > 50 {
			t.Error("Not an efficient append prev appends", b1, b2)
			return
		}
	}

	//AppendFile cannot scale with the size of the previous append (from piazza)
	u.StoreFile("file1", []byte("A"))
	u.StoreFile("file2", []byte("A"))

	u.AppendFile("file1", []byte("appendappendappendappendappendappendappendappendappend"+
		"appendappendappendappendappendappendappendappendappend"+"appendappendappendappendappendappendappendappendappend"+
		"appendappendappendappendappendappendappendappendappend"+"appendappendappendappendappendappendappendappendappend"))

	userlib.DatastoreResetBandwidth()
	u.AppendFile("file1", []byte("B"))
	b1 = userlib.DatastoreGetBandwidth()
	userlib.DatastoreResetBandwidth()
	u.AppendFile("file2", []byte("B"))
	b2 = userlib.DatastoreGetBandwidth()

	difference = b1 - b2

	if difference < 0 {
		if -1*difference > 50 {
			t.Error("Not an efficient append size prev appends", b1, b2)
			return
		}
	} else {
		if difference > 50 {
			t.Error("Not an efficient append size prev appends", b1, b2)
			return
		}
	}

}

func TestNilUser(t *testing.T) {
	clear()

	_, err := InitUser("", "hello")
	if err == nil {
		t.Error("Didn't catch that we can't have empty username", err)
		return
	}

	_, err = InitUser("alice", "")
	if err == nil {
		t.Error("Didn't catch that we can't have empty password", err)
		return
	}
}

func TestEmptyFilename(t *testing.T) {
	clear()

	alice, err := InitUser("alice", "hello")
	if err != nil {
		t.Error("Can't create user alice", err)
		return
	}

	bob, err := InitUser("bob", "hello")
	if err != nil {
		t.Error("Can't create user bob ", err)
		return
	}

	v := []byte("Storing to an empty file name")
	err = alice.StoreFile("", v)
	if err != nil {
		t.Error("failed to store with an empty filename", err)
		return
	}

	_, err = alice.LoadFile("")
	if err != nil {
		t.Error("failed to load with an empty filename", err)
		return
	}

	accessToken, err := alice.ShareFile("", "bob")
	if err != nil {
		t.Error("failed to share with an empty filename", err)
		return
	}

	err = bob.ReceiveFile("", "alice", accessToken)
	if err != nil {
		t.Error("failed to receive with an empty filename", err)
		return
	}

	bob_v := []byte("Bob's appending to an empty filename!")
	err = bob.AppendFile("", bob_v)
	if err != nil {
		t.Error("failed to append with an empty filename", err)
		return
	}

	err = alice.RevokeFile("", "bob")
	if err != nil {
		t.Error("failed to revoke bob from an empty filename", err)
		return
	}
}

func TestShareRevoke(t *testing.T) {
	clear()

	alice, err := InitUser("alice", "hello")
	if err != nil {
		t.Error("Can't create user alice", err)
		return
	}

	bob, err := InitUser("bob", "hello")
	if err != nil {
		t.Error("Can't create user bob ", err)
		return
	}

	v := []byte("Storing to an empty file name")
	err = alice.StoreFile("", v)
	if err != nil {
		t.Error("failed to store with an empty filename", err)
		return
	}

	_, err = alice.ShareFile("", "bob")
	if err != nil {
		t.Error("failed to share with an empty filename", err)
		return
	}

	err = alice.RevokeFile("", "bob")
	if err != nil {
		t.Error("failed to revoke bob from an empty filename", err)
		return
	}

	_, err = bob.LoadFile("")
	if err == nil {
		t.Error("did not correctly revoke from bob", err)
		return
	}

}

func TestRevokeAttack(t *testing.T) {
	clear()

	alice, err := InitUser("alice", "hello")
	if err != nil {
		t.Error("Can't create user alice", err)
		return
	}

	bob, err := InitUser("bob", "hello")
	if err != nil {
		t.Error("Can't create user bob ", err)
		return
	}

	v := []byte("Storing to an empty file name")
	err = alice.StoreFile("", v)
	if err != nil {
		t.Error("failed to store with an empty filename", err)
		return
	}

	accessToken, err := alice.ShareFile("", "bob")
	if err != nil {
		t.Error("failed to share with an empty filename", err)
		return
	}

	err = bob.ReceiveFile("", "alice", accessToken)
	if err != nil {
		t.Error("did not correctly revoke from bob", err)
		return
	}

	_, err = bob.LoadFile("")
	if err != nil {
		t.Error("Bob failed to load file", err)
		return
	}

	err = alice.RevokeFile("", "bob")
	if err != nil {
		t.Error("failed to revoke bob from an empty filename", err)
		return
	}

	err = bob.ReceiveFile("", "alice", accessToken)
	if err == nil {
		t.Error("did not correctly revoke from bob", err)
		return
	}

}

func TestDifUsersSameFile(t *testing.T) {
	clear()

	alice, err := InitUser("alice", "hello")
	if err != nil {
		t.Error("Can't create user alice", err)
		return
	}

	bob, err := InitUser("bob", "hello")
	if err != nil {
		t.Error("Can't create user bob ", err)
		return
	}

	v := []byte("Storing to an empty file name")
	err = alice.StoreFile("", v)
	if err != nil {
		t.Error("failed to store with an empty filename", err)
		return
	}

	err = bob.StoreFile("", v)
	if err != nil {
		t.Error("failed to store with an empty filename", err)
		return
	}

}

func TestNonExistentUsers(t *testing.T) {
	clear()

	_, err := GetUser("alice", "i totally exist")
	if err == nil {
		t.Error("Failed to recognize Alice is not a real user to get.", err)
		return
	}

	v := []byte("dummy data")

	InitUser("dummy", "hello")
	charlie, _ := InitUser("charlie", "fubar")

	// existent user share with non-existent
	err = charlie.StoreFile("file2", v)
	if err != nil {
		t.Error("Failed to store file for Charlie.", err)
		return
	}
	_, err = charlie.ShareFile("file2", "alice")
	if err == nil {
		t.Error("Failed to recognize Charlie cannot share with Alice who DNE.", err)
		return
	}
	// non-existent receive from existent
	accessToken, _ := charlie.ShareFile("file2", "dummy")

	err = charlie.ReceiveFile("file2", "alice", accessToken)
	if err == nil {
		t.Error("Failed to recognize Alice DNE so can't receive from Charlie.", err)
		return
	}

	// existent tries to revoke from non-existent
	err = charlie.RevokeFile("file2", "bob")
	if err == nil {
		t.Error("Failed to recognize Charlie cannot revoke from Bob because Bob DNE.", err)
		return
	}
}
