Skip to content

Commit

Permalink
Merge pull request #6 from qmuntal/improve-errors
Browse files Browse the repository at this point in the history
Improve IO error handling
  • Loading branch information
qmuntal authored Oct 18, 2019
2 parents 02e6933 + 75c178a commit cde29c1
Show file tree
Hide file tree
Showing 11 changed files with 925 additions and 924 deletions.
48 changes: 25 additions & 23 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@


language: go
go_import_path: github.com/qmuntal/opc

go:
- 1.10.x
- 1.11.x

env:
- GO111MODULE=on

notifications:
- email: false

before_script:
- go get -u github.com/mattn/goveralls
- go get -u golang.org/x/tools/cmd/cover
- go get -t -v .

script:
- go test . -coverprofile=coverage.out -race -timeout=5s
- $GOPATH/bin/goveralls -coverprofile=coverage.out -service=travis-ci


language: go
go_import_path: github.com/qmuntal/opc

go:
- 1.10.x
- 1.11.x
- 1.12.x
- 1.13.x

env:
- GO111MODULE=on

notifications:
- email: false

before_script:
- go get -u github.com/mattn/goveralls
- go get -u golang.org/x/tools/cmd/cover
- go get -t -v .

script:
- go test . -coverprofile=coverage.out -race -timeout=5s
- $GOPATH/bin/goveralls -coverprofile=coverage.out -service=travis-ci
4 changes: 0 additions & 4 deletions Makefile

This file was deleted.

120 changes: 60 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,60 +1,60 @@
# opc

[![Documentation](https://godoc.org/github.com/qmuntal/opc?status.svg)](https://godoc.org/github.com/qmuntal/opc)
[![Build Status](https://travis-ci.org/qmuntal/opc.svg?branch=master)](https://travis-ci.org/qmuntal/opc)
[![Go Report Card](https://goreportcard.com/badge/github.com/qmuntal/opc)](https://goreportcard.com/report/github.com/qmuntal/opc)
[![codecov](https://coveralls.io/repos/github/qmuntal/opc/badge.svg)](https://coveralls.io/github/qmuntal/opc?branch=master)
[![codeclimate](https://codeclimate.com/github/qmuntal/opc/badges/gpa.svg)](https://codeclimate.com/github/qmuntal/opc)
[![License](https://img.shields.io/badge/License-BSD%202--Clause-orange.svg)](https://opensource.org/licenses/BSD-2-Clause)
[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go)

Package opc implements the ISO/IEC 29500-2, also known as the [Open Packaging Convention](https://en.wikipedia.org/wiki/Open_Packaging_Conventions).

The Open Packaging specification describes an abstract model and physical format conventions for the use of XML, Unicode, ZIP, and other openly available technologies and specifications to organize the content and resources of a document within a package.

The OPC is the foundation technology for many new file formats: .docx, .pptx, .xlsx, .3mf, .dwfx, ...

## Features
- [x] Package reader and writer
- [x] Package core properties and relationships
- [x] Part relationships
- [x] ZIP mapping
- [x] Package, relationships and parts validation against specs
- [ ] Part interleaved pieces
- [ ] Digital signatures

## Examples
### Write
```go
// Create a file to write our archive to.
f, _ := os.Create("example.xlsx")

// Create a new OPC archive.
w := opc.NewWriter(f)

// Create a new OPC part.
name := opc.NormalizePartName("docs\\readme.txt")
part, _ := w.Create(name, "text/plain")

// Write content to the part.
part.Write([]byte("This archive contains some text files."))

// Make sure to check the error on Close.
w.Close()
```

### Read
```go
r, _ := opc.OpenReader("testdata/test.xlsx")
defer r.Close()

// Iterate through the files in the archive,
// printing some of their contents.
for _, f := range r.Files {
fmt.Printf("Contents of %s with type %s :\n", f.Name, f.ContentType)
rc, _ := f.Open()
io.CopyN(os.Stdout, rc, 68)
rc.Close()
fmt.Println()
}
```
# opc

[![Documentation](https://godoc.org/github.com/qmuntal/opc?status.svg)](https://godoc.org/github.com/qmuntal/opc)
[![Build Status](https://travis-ci.com/qmuntal/opc.svg?branch=master)](https://travis-ci.com/qmuntal/opc)
[![Go Report Card](https://goreportcard.com/badge/github.com/qmuntal/opc)](https://goreportcard.com/report/github.com/qmuntal/opc)
[![codecov](https://coveralls.io/repos/github/qmuntal/opc/badge.svg)](https://coveralls.io/github/qmuntal/opc?branch=master)
[![codeclimate](https://codeclimate.com/github/qmuntal/opc/badges/gpa.svg)](https://codeclimate.com/github/qmuntal/opc)
[![License](https://img.shields.io/badge/License-BSD%202--Clause-orange.svg)](https://opensource.org/licenses/BSD-2-Clause)
[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go)

Package opc implements the ISO/IEC 29500-2, also known as the [Open Packaging Convention](https://en.wikipedia.org/wiki/Open_Packaging_Conventions).

The Open Packaging specification describes an abstract model and physical format conventions for the use of XML, Unicode, ZIP, and other openly available technologies and specifications to organize the content and resources of a document within a package.

The OPC is the foundation technology for many new file formats: .docx, .pptx, .xlsx, .3mf, .dwfx, ...

## Features
- [x] Package reader and writer
- [x] Package core properties and relationships
- [x] Part relationships
- [x] ZIP mapping
- [x] Package, relationships and parts validation against specs
- [ ] Part interleaved pieces
- [ ] Digital signatures

## Examples
### Write
```go
// Create a file to write our archive to.
f, _ := os.Create("example.xlsx")

// Create a new OPC archive.
w := opc.NewWriter(f)

// Create a new OPC part.
name := opc.NormalizePartName("docs\\readme.txt")
part, _ := w.Create(name, "text/plain")

// Write content to the part.
part.Write([]byte("This archive contains some text files."))

// Make sure to check the error on Close.
w.Close()
```

### Read
```go
r, _ := opc.OpenReader("testdata/test.xlsx")
defer r.Close()

// Iterate through the files in the archive,
// printing some of their contents.
for _, f := range r.Files {
fmt.Printf("Contents of %s with type %s :\n", f.Name, f.ContentType)
rc, _ := f.Open()
io.CopyN(os.Stdout, rc, 68)
rc.Close()
fmt.Println()
}
```
5 changes: 2 additions & 3 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ var errorsString = map[int]string{
127: "a relationship type cannot be empty",
128: "a relationship target URI reference shall be a URI or a relative reference",
129: "a relationship target URI must be relative if the TargetMode is Internal",
204: "a content type must be Override or Default",
205: "a Default content type shall not have more than one content type for each extension and a Override shall not have more than one content type for each PartName",
206: "a package shall not have an empty extension in a Default element",
208: "a part content type shall appear in [Content_Types].xml",
Expand Down Expand Up @@ -74,7 +73,7 @@ func (e *Error) RelationshipID() string {
func (e *Error) Error() string {
s, ok := errorsString[e.code]
if !ok {
panic("undefined error")
panic("opc: undefined error")
}
return fmt.Sprintf("OPC: Part='%s' | Reason='%s'", e.partName, s)
return fmt.Sprintf("opc: %s: %s", e.partName, s)
}
178 changes: 89 additions & 89 deletions errors_test.go
Original file line number Diff line number Diff line change
@@ -1,89 +1,89 @@
package opc

import (
"testing"
)

func TestError_Code(t *testing.T) {
tests := []struct {
name string
e *Error
want int
}{
{"empty", new(Error), 0},
{"base", newError(1, "base"), 1},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.e.Code(); got != tt.want {
t.Errorf("Error.Code() = %v, want %v", got, tt.want)
}
})
}
}

func TestError_PartName(t *testing.T) {
tests := []struct {
name string
e *Error
want string
}{
{"empty", new(Error), ""},
{"base", &Error{partName: "base"}, "base"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.e.PartName(); got != tt.want {
t.Errorf("Error.PartName() = %v, want %v", got, tt.want)
}
})
}
}

func TestError_Error(t *testing.T) {
tests := []struct {
name string
e *Error
want string
wantPanic bool
}{
{"base", &Error{101, "/doc.xml", ""}, "OPC: Part='/doc.xml' | Reason='a part name shall not be empty'", false},
{"panic", &Error{0, "/doc.xml", ""}, "", true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
if !tt.wantPanic {
t.Errorf("Error.Error() want panic")
}
}
}()
if got := tt.e.Error(); got != tt.want {
t.Errorf("Error.Error() = %v, want %v", got, tt.want)
return
}
if tt.wantPanic {
t.Error("Error.Error() want error")
}
})
}
}

func TestError_RelationshipID(t *testing.T) {
tests := []struct {
name string
e *Error
want string
}{
{"empty", new(Error), ""},
{"base", newErrorRelationship(101, "/doc.xml", "21211"), "21211"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.e.RelationshipID(); got != tt.want {
t.Errorf("Error.RelationshipID() = %v, want %v", got, tt.want)
}
})
}
}
package opc

import (
"testing"
)

func TestError_Code(t *testing.T) {
tests := []struct {
name string
e *Error
want int
}{
{"empty", new(Error), 0},
{"base", newError(1, "base"), 1},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.e.Code(); got != tt.want {
t.Errorf("Error.Code() = %v, want %v", got, tt.want)
}
})
}
}

func TestError_PartName(t *testing.T) {
tests := []struct {
name string
e *Error
want string
}{
{"empty", new(Error), ""},
{"base", &Error{partName: "base"}, "base"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.e.PartName(); got != tt.want {
t.Errorf("Error.PartName() = %v, want %v", got, tt.want)
}
})
}
}

func TestError_Error(t *testing.T) {
tests := []struct {
name string
e *Error
want string
wantPanic bool
}{
{"base", &Error{101, "/doc.xml", ""}, "opc: /doc.xml: a part name shall not be empty", false},
{"panic", &Error{0, "/doc.xml", ""}, "", true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
if !tt.wantPanic {
t.Errorf("Error.Error() want panic")
}
}
}()
if got := tt.e.Error(); got != tt.want {
t.Errorf("Error.Error() = %v, want %v", got, tt.want)
return
}
if tt.wantPanic {
t.Error("Error.Error() want error")
}
})
}
}

func TestError_RelationshipID(t *testing.T) {
tests := []struct {
name string
e *Error
want string
}{
{"empty", new(Error), ""},
{"base", newErrorRelationship(101, "/doc.xml", "21211"), "21211"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.e.RelationshipID(); got != tt.want {
t.Errorf("Error.RelationshipID() = %v, want %v", got, tt.want)
}
})
}
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module github.com/qmuntal/opc

require github.com/stretchr/testify v1.3.0

go 1.13
Loading

0 comments on commit cde29c1

Please sign in to comment.