Skip to content

Commit

Permalink
Merge 15acd92 into 2000701
Browse files Browse the repository at this point in the history
  • Loading branch information
srishanbhattarai committed May 17, 2020
2 parents 2000701 + 15acd92 commit 8a32313
Show file tree
Hide file tree
Showing 13 changed files with 346 additions and 115 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ install: go get -t ./...
script:
- make test
- make cover
- make cross
- $GOPATH/bin/goveralls -coverprofile=coverage.out -service=travis-ci
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
test:
- go test -v ./...

cross:
- go build -o bin/cross cmd/cross/main.go
- ./bin/cross cmd/cross/reference.json

cover:
- go test -v -covermode=count -coverprofile=coverage.out ./...

9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ Nepcal is a command line tool and a library that provides several functionalitie
* [Today's date and day](#todays-date-and-day)
* [Convert an A.D. date to B.S.](#convert-an-ad-date-to-bs)
* [Convert a B.S. date to A.D.](#convert-a-bs-date-to-ad)
* [Contributing](#contributing)
* [Library/Programmatic usage](#library)
* [Acknowledgements](#acknowledgements)
* [Contributing](#contributing)
* [License](#license)

## Command Line
Expand Down Expand Up @@ -113,6 +114,12 @@ December 3, 1996 Tuesday

If you would like to use `nepcal` as a Go library, the best reference is the [Godoc](https://godoc.org/github.com/srishanbhattarai/nepcal/nepcal) documentation for this package which should be fairly easy to navigate. The CLI tool is also built on this library. However, there are additional functionalities provided in the library that are not relevant in the CLI, for example the [`NumDaysSpanned()`](https://godoc.org/github.com/srishanbhattarai/nepcal/nepcal#Time.NumDaysSpanned) method.

## Acknowledgements

`nepcal` uses [`nepcal.com`](http://nepcal.com/) as the source of information used to create this tool. Among several sources, they were deemed most reliable.

The name `nepcal` was independently chosen for this project which happened to coincide with the website.

## Contributing

Please file an issue if you have any problems with `nepcal` or, have a look at the issues page for contributing on existing issues. Also, read the [code of conduct](https://github.com/srishanbhattarai/nepcal/blob/master/CODE_OF_CONDUCT.md).
Expand Down
12 changes: 12 additions & 0 deletions cmd/cross/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# cross

The `cross` binary is meant for internal uses to verify the correctness of the date conversions and to make sure there
are no regressions in correctness.

During the course of development of `nepcal`, there were several test cases added to make sure that things converted correctly.
Several bugs and edge cases have been found/reported, and subsequently squashed. However, the guarantee that *all* such cases
have been resolved could not be provided. This was further compounded by the fact that different sources on this matter present conflicting information
for several edge cases.

The project now uses `nepcal.com` as the source of truth for the data that it uses and this binary checks every possible date
against the data dump from that website (`reference.json`).
165 changes: 165 additions & 0 deletions cmd/cross/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package main

import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"strconv"
"time"

"github.com/fatih/color"
"github.com/srishanbhattarai/nepcal/nepcal"
)

// Copied from "nepcal/constants.go" as these are not public but are needed for this specific use case.
const (
adLBoundY = 1918
adLBoundM = int(time.April)
adLBoundD = 13
)

// DateMapEntry is each entry in the array of results returned by the reference URL.
type DateMapEntry struct {
NpYear int `json:"npYear"`
NpMonth int `json:"npMonth"`
NpDay int `json:"npDay"`
EnYear int `json:"enYear"`
EnMonth int `json:"enMonth"`
EnDay int `json:"enDay"`
}

// Get the reference entries, properly serialized, and sliced for only the range for which we support.
func getRefEntries(refEntriesFile string) ([]DateMapEntry, error) {
// Read file.
b, err := ioutil.ReadFile(refEntriesFile)
if err != nil {
return nil, err
}

// Marshal
var entries []DateMapEntry
err = json.Unmarshal(b, &entries)
if err != nil {
return nil, err
}

// Figure out the index at which the first entry for adLBoundY exists.
index := 0
for k, v := range entries {
if v.EnYear == adLBoundY && v.EnMonth == adLBoundM && v.EnDay == adLBoundD {
index = k
break
}
}

cov := (float64(len(entries)-index+1) / float64(len(entries))) * 100
fmt.Printf("Starting at index: %d, percentage coverage of reference: %.2f\n", index, cov)

return entries[index:], nil
}

// Get entries for the same date range as above but from the nepcal library, as specified using 'count'.
// Panics if date happens to be out of bounds, should never happen.
func getNepcalEntries(count int) []DateMapEntry {
entries := make([]DateMapEntry, count)

t := time.Date(adLBoundY, time.Month(adLBoundM), adLBoundD, 0, 0, 0, 0, time.UTC)
i := 0

for i < count {
bs, err := nepcal.FromGregorian(t)
if err != nil {
panic(fmt.Sprintf("Invariant violation: %v, %s\n", err, t))
}

entry := DateMapEntry{
NpYear: bs.Year(),
NpMonth: int(bs.Month()),
NpDay: bs.Day(),
EnYear: t.Year(),
EnMonth: int(t.Month()),
EnDay: t.Day(),
}

entries[i] = entry

t = t.AddDate(0, 0, 1)

i++
}

return entries
}

// Format entry into string.
func fmtEntry(e DateMapEntry) string {
us := fmt.Sprintf("(en) %d-%d-%d", e.EnYear, e.EnMonth, e.EnDay)
np := fmt.Sprintf("(np) %d-%d-%d", e.NpYear, e.NpMonth, e.NpDay)

return fmt.Sprintf("%s ==> %s", us, np)
}

// diff the two data sources and print to stdout.
// us = entries created by this library
// them = external entries for validation.
func diffEntries(us, them []DateMapEntry) int {
if len(us) != len(them) {
panic(fmt.Sprintf("Invariant violation mismatching lengths; us = %v, them = %v\n", us, them))
}

type failure struct {
index int
us DateMapEntry
them DateMapEntry
}
var failures []failure

// Find cases where dates don't match
for i := 0; i < len(us); i++ {
if us[i] != them[i] {
failures = append(failures, failure{i, us[i], them[i]})
}
}

// Pretty print diffs
for _, v := range failures {
fmt.Printf("Inconsistency: %s\n", color.BlueString(strconv.Itoa(v.index)))

us := fmt.Sprintf("- (actual) %s", fmtEntry(v.us))
them := fmt.Sprintf("+ (expected) %s", fmtEntry(v.them))

fmt.Printf(fmt.Sprintf("%s\n", color.RedString(us)))
fmt.Printf(fmt.Sprintf("%s\n\n", color.GreenString(them)))
}

fmt.Printf(fmt.Sprintf("Number of inconsistencies: %s\n", color.YellowString(strconv.Itoa(len(failures)))))

failureRate := (float64(len(failures)) / float64(len(us))) * 100
fmt.Printf(fmt.Sprintf("Failure percentage: %s\n", color.YellowString(fmt.Sprintf("%.2f", failureRate))))

return len(failures)
}

func main() {
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "Please provide the reference JSON file.")
os.Exit(1)
}

refEntries, err := getRefEntries(os.Args[1])
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}

libEntries := getNepcalEntries(len(refEntries))

n := diffEntries(libEntries, refEntries)

if n == 0 {
os.Exit(0)
} else {
os.Exit(1)
}
}
1 change: 1 addition & 0 deletions cmd/cross/reference.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/srishanbhattarai/nepcal
go 1.13

require (
github.com/fatih/color v1.9.0
github.com/stretchr/testify v1.5.1
github.com/urfave/cli/v2 v2.2.0
)
9 changes: 9 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSY
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
Expand All @@ -14,6 +21,8 @@ github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/urfave/cli/v2 v2.2.0 h1:JTTnM6wKzdA0Jqodd966MVj4vWbbquZykeX1sKbe2C4=
github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
Expand Down
Loading

0 comments on commit 8a32313

Please sign in to comment.