add prompt dir
parent
1c06e472c2
commit
7e9b85d0f4
|
|
@ -0,0 +1,47 @@
|
|||
# Welcome to the Digits Go Work Sample!
|
||||
|
||||
At Digits, we care deeply about who joins our team, so congrats on making it to this round in the process!
|
||||
|
||||
One of our goals as we continue the conversation is to learn more about how you think about and solve technical problems, so that we can get a sense of what it will be like working together day-to-day. That's what we're going to focus on here.
|
||||
|
||||
**First things first:** If you have prior experience with go, please **only** spend 3 hours on this. If you are new to go, please allow yourself 4 hours.
|
||||
|
||||
We've designed it so there is more work here than it's possible for anyone to finish in 3 (or 4) hours, so don't worry about it. We're looking for *quality* of engineering, not *quantity* of engineering. Seriously :)
|
||||
|
||||
And, of course, feel free to use any resources you would in your normal day-to-day work experience: Google, StackOverflow, etc.
|
||||
|
||||
Please take the time to format your code using [gofmt](https://pkg.go.dev/cmd/gofmt) (trivial to do if you are using [VSCode](https://code.visualstudio.com/docs/languages/go#_formatting)). If you are new to go, [this](https://gobyexample.com/) is a great resource to get some pointers.
|
||||
|
||||
Without further ado, here's a quick intro to the basics...
|
||||
|
||||
<hr>
|
||||
|
||||
### Setting Up...
|
||||
|
||||
Make sure you have Go [installed](https://golang.org/doc/install). You'll need at least 1.13.
|
||||
|
||||
Then, head on over to `analyzer_test.go` where the instructions continue...
|
||||
|
||||
*When your 3 hours are up, follow the instructions at the bottom of this README to submit your work sample, along with a few written-response questions. Happy coding!!*
|
||||
|
||||
<hr>
|
||||
|
||||
## If You're Totally Stuck :-(
|
||||
|
||||
If the instructions above don't work for any reason, or you get hopelessly stuck while coding, don't stress! Send us a note at <hello@digits.com> and we'll help get you sorted!
|
||||
|
||||
## When Your 3 Hours Are Up :-)
|
||||
|
||||
Pencils down! We know how tempting it is to keep going, so we really appreciate you sticking to the time limit :)
|
||||
|
||||
To submit your work sample, Zip up this directory (everything except the .build sub-directory) and email it back to us along with your written responses to these questions:
|
||||
|
||||
1. How would you evaluate your work? What went well? What would you do differently?
|
||||
1. What was the biggest insight you gained, or thing you learned, while working on this?
|
||||
1. If you were to add another test challenge to this, what would it be? Why?
|
||||
|
||||
Thanks again for taking the time to complete this, and we're really looking forward to continuing the conversation!
|
||||
|
||||
**Happy coding!!**
|
||||
|
||||
—Team Digits
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package analyzer
|
||||
|
||||
import "math"
|
||||
|
||||
type Amount float64
|
||||
|
||||
// Rounded rounds a float to the number of places specified.
|
||||
func (amount Amount) Rounded(places int) Amount {
|
||||
p := math.Pow10(places)
|
||||
return Amount(math.Round(float64(amount)*p) / p)
|
||||
}
|
||||
|
||||
// FormatUSD formats Amount as a string in US dollars.
|
||||
func (amount Amount) FormatUSD() string {
|
||||
// TODO: Not implemented.
|
||||
// Hint: Number localization gets tricky. Can you find a library to help?
|
||||
return ""
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
package analyzer
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRounded(t *testing.T) {
|
||||
type args struct {
|
||||
num Amount
|
||||
places int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want Amount
|
||||
}{
|
||||
{
|
||||
name: "zero",
|
||||
args: args{num: 0.0, places: 2},
|
||||
want: 0.0,
|
||||
},
|
||||
{
|
||||
name: "negative",
|
||||
args: args{num: -30.1, places: 2},
|
||||
want: -30.1,
|
||||
},
|
||||
{
|
||||
name: "long",
|
||||
args: args{num: 500.123456789, places: 3},
|
||||
want: 500.123,
|
||||
},
|
||||
{
|
||||
name: "short",
|
||||
args: args{num: 500.523456789, places: 1},
|
||||
want: 500.5,
|
||||
},
|
||||
{
|
||||
name: "money",
|
||||
args: args{num: 3.50, places: 2},
|
||||
want: 3.50,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.args.num.Rounded(tt.args.places); got != tt.want {
|
||||
t.Errorf("Rounded() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatUSD(t *testing.T) {
|
||||
type args struct {
|
||||
dollars Amount
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "zero",
|
||||
args: args{dollars: 0.0},
|
||||
want: "$0.00",
|
||||
},
|
||||
{
|
||||
name: "positive",
|
||||
args: args{dollars: 13.35423},
|
||||
want: "$13.35",
|
||||
},
|
||||
{
|
||||
name: "negative",
|
||||
args: args{dollars: -28.44},
|
||||
want: "-$28.44",
|
||||
},
|
||||
{
|
||||
name: "large",
|
||||
args: args{dollars: 56000.03},
|
||||
want: "$56,000.03",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.args.dollars.FormatUSD(); got != tt.want {
|
||||
t.Errorf("FormatUSD() = %q, want %q", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package analyzer
|
||||
|
||||
import "errors"
|
||||
|
||||
// Analyzer processes Transactions and generates reports.
|
||||
type Analyzer struct {
|
||||
// The list of Transactions available to analyze.
|
||||
transactions Transactions
|
||||
}
|
||||
|
||||
// Add adds unique transactions to Analyzer.
|
||||
func (anz *Analyzer) Add(transactions Transactions) int {
|
||||
anz.transactions = append(anz.transactions, transactions...)
|
||||
return len(transactions)
|
||||
}
|
||||
|
||||
// TransactionCount is the number of unique Transactions.
|
||||
func (anz *Analyzer) TransactionCount() int {
|
||||
return len(anz.transactions)
|
||||
}
|
||||
|
||||
// TransactionsAmount is the total amount of all the transactions.
|
||||
func (anz *Analyzer) TransactionsAmount() Amount {
|
||||
return anz.transactions.Sum()
|
||||
}
|
||||
|
||||
// LargestTransaction is the single largest transaction, ranked by
|
||||
// the absolute value of the transaction amount. Returns an error if there
|
||||
// are no transactions.
|
||||
//
|
||||
// - Note: Large negative transactions are still large--it just means the
|
||||
// money moved the other direction.
|
||||
func (anz *Analyzer) LargestTransaction() (Transaction, error) {
|
||||
// TODO: Not implemented.
|
||||
return Transaction{}, errors.New("not implemented")
|
||||
}
|
||||
|
||||
// ByCategory groups the transactions by category and returns a map of
|
||||
// category name to the list of transactions that are part of that category.
|
||||
func (anz *Analyzer) ByCategory() map[string]Transactions {
|
||||
// TODO: Not implemented.
|
||||
return nil
|
||||
}
|
||||
|
||||
// BigSpenderReport generates our Big Spender Report.
|
||||
//
|
||||
// "Big spenders" are defined as those people who, in aggregate
|
||||
// across their transactions, have spent more than 2 standard
|
||||
// deviations above the mean spender.
|
||||
//
|
||||
// The method determines who they are and generates a well-formatted
|
||||
// report to call them out.
|
||||
func (anz *Analyzer) BigSpenderReport() string {
|
||||
report := `
|
||||
Digits Big Spenders Report
|
||||
------------------------------------------------------
|
||||
Name Amount
|
||||
------------------------------------------------------`
|
||||
|
||||
// TODO: Not implemented.
|
||||
// TODO: As a reminder, we're looking for well-factored, well-organized
|
||||
// code. We encourage you to refactor, change, or add to any part
|
||||
// of the non-test code as you see fit!
|
||||
report += ""
|
||||
|
||||
return report
|
||||
}
|
||||
|
||||
// New creates a new Analyzer with an empty set of transactions
|
||||
func New() *Analyzer {
|
||||
return &Analyzer{transactions: Transactions{}}
|
||||
}
|
||||
|
|
@ -0,0 +1,279 @@
|
|||
// At Digits, we care deeply about Test-Driven Development. If the build is "green",
|
||||
// we ship it. We do not have a QA team, and we do not have an Ops team. Everyone is
|
||||
// responsible for their code end-to-end, which means we're highly motivated to make it
|
||||
// as stable and as secure as possible. We do this with automated tests.
|
||||
//
|
||||
// If you run `go test` on the command line, you'll see that we have some problems here.
|
||||
// Only one test in the project passes!
|
||||
//
|
||||
// This is where you come in.
|
||||
//
|
||||
// We need you to go through the tests and help us fix them. Only spend 3 hours on this,
|
||||
// and don't worry about fixing all of them. We've designed it so there is more work here
|
||||
// than it is possible for anyone to finish in 3 hours, so don't worry about it. The tests
|
||||
// build on each other, so they will be generally easier if you go in order, but feel free
|
||||
// to jump around if you get stuck on one of them.
|
||||
//
|
||||
// Let's be clear: you are NOT being evaluated on how many tests you fix. We want to see
|
||||
// thoughtful, easy-to-read, well-performing, secure, and well-documented code. At Digits,
|
||||
// it's quality over quantity every day of the week.
|
||||
//
|
||||
// One last tip for you: You won't need to change any code in this file. Start by familiarizing
|
||||
// yourself with the rest of the codebase, because that's where all your work will be.
|
||||
//
|
||||
// Best of luck, and we really appreciate all your help getting these tests to pass! Remember to
|
||||
// stop after 3 hours wherever you are -- we know how tempting it is to keep going :-)
|
||||
//
|
||||
// -- Team Digits
|
||||
package analyzer_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
analyzer "github.com/digits/WorkSample-Go"
|
||||
)
|
||||
|
||||
// This work sample revolves around parsing and analyzing credit card transactions,
|
||||
// which is something pretty core to what we work on at Digits!
|
||||
//
|
||||
// This is the Analyzer instance that the tests in this file will run against.
|
||||
func newAnalyzer(t *testing.T) *analyzer.Analyzer {
|
||||
txs, err := analyzer.TransactionsFromFile("testdata/transactions.json")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
anz := analyzer.New()
|
||||
anz.Add(txs)
|
||||
return anz
|
||||
}
|
||||
|
||||
// The SampleTransactionData contains 188 distinct transactions.
|
||||
//
|
||||
// Let's validate that the analyzer sees all of them.
|
||||
//
|
||||
// - Note: This test should already be working correctly. No need to do anything here.
|
||||
func TestAnalyzer_NewFromFile(t *testing.T) {
|
||||
anz := newAnalyzer(t)
|
||||
|
||||
if n := anz.TransactionCount(); n != 188 {
|
||||
t.Errorf("expected 188 transactions, got %d", n)
|
||||
}
|
||||
}
|
||||
|
||||
// Alright, your work starts here!
|
||||
//
|
||||
// The SampleTransactionData contains $48,501.17 worth of transactions, but something
|
||||
// here isn't working. Let's make sure `Transactions.Sum()` is implemented correctly.
|
||||
func TestAnalyzer_TransctionsSum(t *testing.T) {
|
||||
anz := newAnalyzer(t)
|
||||
|
||||
if amount := anz.TransactionsAmount(); amount.Rounded(2) != 48_501.17 {
|
||||
t.Errorf("expected 48,501.17 in transactions, got %f", amount)
|
||||
}
|
||||
}
|
||||
|
||||
// Next, let's find the largest transaction. Hmm, this one doesn't seem to be working either.
|
||||
func TestAnalyzer_LargestTransaction(t *testing.T) {
|
||||
anz := newAnalyzer(t)
|
||||
|
||||
trn, err := anz.LargestTransaction()
|
||||
if err != nil {
|
||||
t.Errorf("expected nil got %v", err)
|
||||
}
|
||||
|
||||
if trn.Amount != 3_831.2 {
|
||||
t.Errorf("expected largest transaction amount of $3,831.2, got %f", trn.Amount)
|
||||
}
|
||||
}
|
||||
|
||||
// Our analysis won't be accurate unless we make sure to de-duplicate transactions.
|
||||
//
|
||||
// Revamp the way we instantiate our Analyzer so that duplicate Transactions are discarded.
|
||||
// What data structure can you employ to make this easy?
|
||||
//
|
||||
// - Note: Once you get this working, double check that the previous tests still pass!
|
||||
func TestAnalyzer_DuplicatesExcluded(t *testing.T) {
|
||||
anz := newAnalyzer(t)
|
||||
|
||||
txs, err := analyzer.TransactionsFromFile("testdata/transactions.json")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Re-adding the existing transactions should be a no-op.
|
||||
anz.Add(txs)
|
||||
|
||||
if n := anz.TransactionCount(); n != 188 {
|
||||
t.Errorf("expected 188 transactions, got %d", n)
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we know our data has no duplicates, we can get on to some real analysis.
|
||||
//
|
||||
// Let's group the transactions by category to see how often we shopped at Hardware Stores,
|
||||
// and how much we spent on Electrical Contractors.
|
||||
func TestAnalyzer_GroupByCategory(t *testing.T) {
|
||||
anz := newAnalyzer(t)
|
||||
|
||||
categories := anz.ByCategory()
|
||||
|
||||
if trns := categories["HARDWARE STORES"]; len(trns) != 12 {
|
||||
t.Errorf("expected category 'HARDWARE STORES' to have 12 transactions, got %d", len(trns))
|
||||
}
|
||||
|
||||
if trns := categories["ELECTRICAL CONTRACTORS"]; len(trns) != 1 {
|
||||
t.Errorf("expected category 'ELECTRICAL CONTRACTORS' to have 1 transactions, got %d", len(trns))
|
||||
}
|
||||
|
||||
if trns := categories["ELECTRICAL CONTRACTORS"]; trns.Sum() != 89.0 {
|
||||
t.Errorf("expected category 'ELECTRICAL CONTRACTORS' to have a total amount of $89.00, got %f", trns.Sum())
|
||||
}
|
||||
}
|
||||
|
||||
// Let's take a break from Transactions, and start preparing our printed reports.
|
||||
//
|
||||
// To do this, we're going to need to be able to attractively print dollar amounts.
|
||||
//
|
||||
// Hop over to `amount_test.go` and get those tests straightened out before continuing.
|
||||
//
|
||||
// With currencies looking sharp, it's time we're able to print whole trasnactions.
|
||||
//
|
||||
// Take a look at `transaction_test.go` and make sure we're properly formatting transactions!
|
||||
|
||||
// Finally, we're ready for our first report! We'll define "big spenders" as people who,
|
||||
// in aggregate across their transactions, have spent more than 2 standard deviations above
|
||||
// the mean spender.
|
||||
//
|
||||
// - Note: No hints this time. You know what to do! :)
|
||||
func TestAnalyzer_BigSpendersReport(t *testing.T) {
|
||||
anz := newAnalyzer(t)
|
||||
|
||||
const sampleReport = `
|
||||
Digits Big Spenders Report
|
||||
------------------------------------------------------
|
||||
Name Amount
|
||||
------------------------------------------------------
|
||||
R. Bowers $5,877.00
|
||||
T. Munday $4,556.60
|
||||
W. Edwards $3,248.79
|
||||
P. Wood $2,888.36
|
||||
------------------------------------------------------`
|
||||
|
||||
report := anz.BigSpenderReport()
|
||||
|
||||
if report != sampleReport {
|
||||
t.Errorf("expected big spender report of:\n%s\n\nGot:\n%s", sampleReport, report)
|
||||
}
|
||||
}
|
||||
|
||||
// Playing with 188 hard-coded transactions is fun but not very interesting.
|
||||
// Now, it's time to load transactions from the network, ~1000 at a time!
|
||||
//
|
||||
// - Warning: You will need an active network connection to complete the next few challenges.
|
||||
func TestAnalyzer_TransactionsFromURLs(t *testing.T) {
|
||||
const transactionsURL = "https://assets.digits.com/uploads/hiring/swift-work-sample/transactions-aa.json"
|
||||
|
||||
txs, err := analyzer.TransactionsFromURLs(transactionsURL)
|
||||
if err != nil {
|
||||
t.Errorf("failed adding transactions from URL (%s): %s", transactionsURL, err)
|
||||
}
|
||||
|
||||
anz := newAnalyzer(t)
|
||||
if n := anz.Add(txs); n != 980 {
|
||||
t.Errorf("expected 980 new transactions, got %d", n)
|
||||
}
|
||||
|
||||
if n := anz.TransactionCount(); n != 1168 {
|
||||
t.Errorf("expected 1168 transactions, got %d", n)
|
||||
}
|
||||
|
||||
const sampleReport = `
|
||||
Digits Big Spenders Report
|
||||
------------------------------------------------------
|
||||
Name Amount
|
||||
------------------------------------------------------
|
||||
J. Heusel $17,832.64
|
||||
G. Hines $14,787.33
|
||||
T. Munday $12,967.93
|
||||
M. Al-Harake $7,454.14
|
||||
R. Bowers $6,368.09
|
||||
P. Lloyd $5,986.06
|
||||
M. Tornakian $5,395.37
|
||||
C. Miller $5,025.00
|
||||
B. Ritthaler $4,897.54
|
||||
J. Potts $4,800.00
|
||||
J. Teel $4,685.82
|
||||
K. Baum $4,533.40
|
||||
K. Boyd $4,488.84
|
||||
A. Hunt $4,424.64
|
||||
A. Kindred $4,329.10
|
||||
V. Yarbrough-Tessman $4,077.30
|
||||
G. Deaver $3,835.00
|
||||
------------------------------------------------------`
|
||||
|
||||
report := anz.BigSpenderReport()
|
||||
|
||||
if report != sampleReport {
|
||||
t.Errorf("expected big spender report of:\n%s\n\nGot:\n%s", sampleReport, report)
|
||||
}
|
||||
}
|
||||
|
||||
// Now that you have one file working, it's time to load Transactions from 10 at once!
|
||||
//
|
||||
// For this challenge, dive into channels, goroutines, and sync.WaitGroup to perform the
|
||||
// requests in parallel.
|
||||
func TestAnalyzer_TransactionsFromURLsConcurrent(t *testing.T) {
|
||||
urls := []string{"aa", "ab", "ac", "ad", "ae", "af", "ag", "ah", "ai", "aj"}
|
||||
|
||||
for i, suffix := range urls {
|
||||
urls[i] = fmt.Sprintf("https://assets.digits.com/uploads/hiring/swift-work-sample/transactions-%s.json", suffix)
|
||||
}
|
||||
|
||||
txs, err := analyzer.TransactionsFromURLs(urls...)
|
||||
if err != nil {
|
||||
t.Errorf("failed adding transactions from URL (%v): %s", urls, err)
|
||||
}
|
||||
|
||||
anz := newAnalyzer(t)
|
||||
|
||||
if n := anz.Add(txs); n != 9661 {
|
||||
t.Errorf("expected 9661 transactions, got %d", n)
|
||||
}
|
||||
|
||||
if n := anz.TransactionCount(); n != 9849 {
|
||||
t.Errorf("expected 9849 transactions, got %d", n)
|
||||
}
|
||||
|
||||
const sampleReport = `
|
||||
Digits Big Spenders Report
|
||||
------------------------------------------------------
|
||||
Name Amount
|
||||
------------------------------------------------------
|
||||
M. Tornakian $149,097.79
|
||||
G. Hines $139,769.73
|
||||
J. Heusel $108,557.26
|
||||
T. Munday $66,767.24
|
||||
R. Bowers $38,639.01
|
||||
S. Fitzpatrick $32,320.23
|
||||
V. Yarbrough-Tessman $29,655.08
|
||||
A. Steanson $28,500.78
|
||||
A. Kindred $24,623.06
|
||||
M. Clark $24,132.51
|
||||
J. Teel $23,729.02
|
||||
S. Earls $22,238.02
|
||||
A. Ropers $22,033.28
|
||||
D. Turner $21,205.21
|
||||
D. Connelly $20,458.27
|
||||
D. Whitefield $20,102.42
|
||||
S. Clawson $19,945.81
|
||||
M. Al-Harake $19,510.29
|
||||
------------------------------------------------------`
|
||||
|
||||
report := anz.BigSpenderReport()
|
||||
|
||||
if report != sampleReport {
|
||||
t.Errorf("expected big spender report of:\n%s\n\nGot:\n%s", sampleReport, report)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
module github.com/digits/WorkSample-Go
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/stretchr/testify v1.4.0
|
||||
golang.org/x/text v0.3.2
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,61 @@
|
|||
package analyzer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Transaction represents a transaction from our upstream source.
|
||||
// URL: https://catalog.data.gov/dataset/purchase-card-pcard-fiscal-year-2014
|
||||
type Transaction struct {
|
||||
Category string `json:"MerchantCategory"`
|
||||
Vendor string
|
||||
Description string
|
||||
AgencyName string
|
||||
CardholderLastName string
|
||||
TransactionDate string
|
||||
Amount Amount `json:",string"`
|
||||
YearMonth string
|
||||
CardholderFirstInitial string
|
||||
AgencyNumber string
|
||||
PostedDate string
|
||||
}
|
||||
|
||||
func (trn Transaction) String() string {
|
||||
// TODO: Not implemented.
|
||||
return ""
|
||||
}
|
||||
|
||||
// Transactions represents a list of Transaction
|
||||
type Transactions []Transaction
|
||||
|
||||
// Sum adds all transactions together.
|
||||
func (trns Transactions) Sum() Amount {
|
||||
// TODO: Not implemented.
|
||||
return 0.0
|
||||
}
|
||||
|
||||
// Count is the number of unique Transactions.
|
||||
func (trns Transactions) Count() int {
|
||||
return len(trns)
|
||||
}
|
||||
|
||||
func TransactionsFromFile(path string) (Transactions, error) {
|
||||
jsonFile, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer jsonFile.Close()
|
||||
|
||||
var transactions Transactions
|
||||
if err := json.NewDecoder(jsonFile).Decode(&transactions); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return transactions, nil
|
||||
}
|
||||
|
||||
func TransactionsFromURLs(url ...string) (Transactions, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package analyzer
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// - Note: The JSON data contains the person's name who made the transaction.
|
||||
// Let's pipe that through so it's available.
|
||||
//
|
||||
// - Note: Pay attention to how we want negative transactions handled.
|
||||
func TestTransaction_String(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
trn Transaction
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "MCCOLLOMS INC",
|
||||
trn: Transaction{
|
||||
CardholderFirstInitial: "R",
|
||||
CardholderLastName: "Bowers",
|
||||
Amount: 3831.20,
|
||||
Vendor: "MCCOLLOMS INC",
|
||||
},
|
||||
want: "R. Bowers spent $3,831.20 at MCCOLLOMS INC",
|
||||
},
|
||||
{
|
||||
name: "QUANTUM ELECTRIC INC",
|
||||
trn: Transaction{
|
||||
CardholderFirstInitial: "B",
|
||||
CardholderLastName: "Adams",
|
||||
Amount: 89.00,
|
||||
Vendor: "QUANTUM ELECTRIC INC",
|
||||
},
|
||||
want: "B. Adams spent $89.00 at QUANTUM ELECTRIC INC",
|
||||
},
|
||||
{
|
||||
name: "MARRIOTT 33716 NEW ORLEAN",
|
||||
trn: Transaction{
|
||||
CardholderFirstInitial: "J",
|
||||
CardholderLastName: "Golliver",
|
||||
Amount: -514.11,
|
||||
Vendor: "MARRIOTT 33716 NEW ORLEAN",
|
||||
},
|
||||
want: "MARRIOTT 33716 NEW ORLEAN refunded J. Golliver $514.11",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.trn.String(); got != tt.want {
|
||||
t.Errorf("Transaction.String() = %q, want %q", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue