Skip to content

Commit

Permalink
add String and Image + unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Achille Roussel committed May 20, 2016
1 parent 2857ef7 commit c368e43
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 55 deletions.
18 changes: 1 addition & 17 deletions CoreFoundation.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ type CFStringRef unsafe.Pointer
// created string.
//
// It is the program's responsibility to release the object returned by this
// function with a call to CFStringRelease or CFRelease.
// function with a call to CFRelease.
//
// https://developer.apple.com/library/ios/documentation/CoreFoundation/Reference/CFStringRef/index.html#//apple_ref/c/func/CFStringCreateWithBytes
func CFStringCreate(s string) CFStringRef {
Expand All @@ -54,22 +54,6 @@ func CFStringCreate(s string) CFStringRef {
))
}

// CFStringRetain increases the reference counter of the string object passed as
// argument.
//
// https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CFTypeRef/#//apple_ref/c/func/CFRetain
func CFStringRetain(s CFStringRef) {
CFRetain(CFTypeRef(s))
}

// CFStringRelease decreases the reference counter of the string object passed
// as argument.
//
// https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CFTypeRef/#//apple_ref/c/func/CFRelease
func CFStringRelease(s CFStringRef) {
CFRelease(CFTypeRef(s))
}

// GoString creates a new Go string value with a content equivalent to the
// CFStringRef object passed as argument.
func GoString(s CFStringRef) string {
Expand Down
6 changes: 3 additions & 3 deletions CoreFoundation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ func TestCFString(t *testing.T) {

for _, test := range tests {
s1 := CFStringCreate(test)
CFStringRetain(s1)
CFStringRelease(s1)
CFRetain(CFTypeRef(s1))
CFRelease(CFTypeRef(s1))

s2 := GoString(s1)
CFStringRelease(s1)
CFRelease(CFTypeRef(s1))

if test != s2 {
t.Errorf(test, "!=", s2)
Expand Down
20 changes: 2 additions & 18 deletions CoreGraphics.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type CGImageRef unsafe.Pointer
//
// The image content is copied by the funciton, it's the program's responsibility
// to free the resources allocated by the returned CGImageRef with a call to
// CGImageRelease or CFRelease.
// CFRelease.
//
// The function supports any image types defined in the standard image package,
// but will panic if the program attempts to create a CGImageRef from an
Expand Down Expand Up @@ -63,7 +63,7 @@ func CGImageCreate(img image.Image) CGImageRef {
// program must ensure that the image.Image value it passed to the function is
// referenced and unmodified for as long as the returned CGImageRef is in use.
// It's the program's responsibility to free the resources allocated by the
// returned CGImageRef with a call to CGImageRelease or CFRelease.
// returned CGImageRef with a call to CFRelease.
//
// The function supports any image types defined in the standard image package,
// but will panic if the program attempts to create a CGImageRef from an
Expand Down Expand Up @@ -99,22 +99,6 @@ func CGImageCreateNoCopy(img image.Image) CGImageRef {
return CGImageRef(cgimg)
}

// CGImageRetain increases the reference counter of the image object passed as
// argument.
//
// https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CFTypeRef/#//apple_ref/c/func/CFRetain
func CGImageRetain(img CGImageRef) {
CFRetain(CFTypeRef(img))
}

// CFImageRelease decreases the reference counter of the image object passed
// as argument.
//
// https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CFTypeRef/#//apple_ref/c/func/CFRelease
func CGImageRelease(img CGImageRef) {
CFRelease(CFTypeRef(img))
}

type imageData struct {
pixels []byte
bpc int
Expand Down
23 changes: 6 additions & 17 deletions CoreGraphics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,21 @@
package cocoa

import (
"bufio"
"image"
"os"
"testing"

_ "image/png"
)

func TestCGImageCreate(t *testing.T) {
img := CGImageCreate(gopher)
CGImageRetain(img)
CGImageRelease(img)
CGImageRelease(img)
CFRetain(CFTypeRef(img))
CFRelease(CFTypeRef(img))
CFRelease(CFTypeRef(img))
}

func TestCGImageCreateNoCopy(t *testing.T) {
img := CGImageCreateNoCopy(gopher)
CGImageRetain(img)
CGImageRelease(img)
CGImageRelease(img)
}

var gopher image.Image

func init() {
f, _ := os.Open("fixtures/gopher.png")
gopher, _, _ = image.Decode(bufio.NewReader(f))
f.Close()
CFRetain(CFTypeRef(img))
CFRelease(CFTypeRef(img))
CFRelease(CFTypeRef(img))
}
50 changes: 50 additions & 0 deletions image.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// +build darwin

package cocoa

import (
"image"
"runtime"
)

// The Image type wraps and manages a CGImageRef value.
//
// The intent for Image values is to provide automatic memory management for
// native values from the Cocoa framework by leveraging the Go GC, basically
// the lifetime of the managed CGImageRef is bound to the lifetime of the
// Image instance.
//
// The Image type also offers an API that betters integrates with Go code by
// implementing standard interfaces and exposing methods.
type Image struct {
ref CGImageRef
}

// NewImage creates a new Image value with a content equivalent to the Go
// image passed as argument.
func NewImage(img image.Image) *Image {
return NewImageWrap(CGImageCreate(img))
}

// NewImageWarp creates a new Image value that wraps the CGImageRef value
// passed as argument.
//
// The returned Image value becomes the owner of the CGImageRef, it will
// automatically release it when it gets garbage collected.
func NewImageWrap(ref CGImageRef) *Image {
img := &Image{ref}
runtime.SetFinalizer(img, (*Image).release)
return img
}

// Ref returns the CGImageRef wrapped by the Image value it is called on.
func (img *Image) Ref() CGImageRef {
return img.ref
}

func (img *Image) release() {
if ref := img.ref; ref != nil {
img.ref = nil
CFRelease(CFTypeRef(ref))
}
}
35 changes: 35 additions & 0 deletions image_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// +build darwin

package cocoa

import (
"bufio"
"image"
"os"
"testing"
)

var gopher image.Image

func init() {
f, _ := os.Open("fixtures/gopher.png")
gopher, _, _ = image.Decode(bufio.NewReader(f))
f.Close()
}

func TestNewImage(t *testing.T) {
img := NewImage(gopher)

if img.Ref() == nil {
t.Error("invalid nil image reference")
}
}

func TestNewImageWrap(t *testing.T) {
img1 := CGImageCreate(gopher)
img2 := NewImageWrap(img1)

if ref := img2.Ref(); ref != img1 {
t.Error("invalid image reference:", ref)
}
}
55 changes: 55 additions & 0 deletions string.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// +build darwin

package cocoa

import "runtime"

// The String type wraps and manages a CFStringRef value.
//
// The intent for String values is to provide automatic memory management for
// native values from the Cocoa framework by leveraging the Go GC, basically
// the lifetime of the managed CFStringRef is bound to the lifetime of the
// String instance.
//
// The String type also offers an API that betters integrates with Go code by
// implementing standard interfaces and exposing methods.
type String struct {
ref CFStringRef
}

// NewString creates a new String value with a content equivalent to the Go
// string passed as argument.
func NewString(s string) *String {
return NewStringWrap(CFStringCreate(s))
}

// NewStringWarp creates a new String value that wraps the CFStringRef value
// passed as argument.
//
// The returned String value becomes the owner of the CFStringRef, it will
// automatically release it when it gets garbage collected.
func NewStringWrap(ref CFStringRef) *String {
s := &String{ref}
runtime.SetFinalizer(s, (*String).release)
return s
}

// String returns the content of the String object as a Go string value.
func (s *String) String() string {
if s.ref == nil {
return ""
}
return GoString(s.ref)
}

// Ref returns the CFStringRef wrapped by the String value it is called on.
func (s *String) Ref() CFStringRef {
return s.ref
}

func (s *String) release() {
if ref := s.ref; ref != nil {
s.ref = nil
CFRelease(CFTypeRef(ref))
}
}
59 changes: 59 additions & 0 deletions string_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// +build darwin

package cocoa

import "testing"

func TestNewString(t *testing.T) {
tests := []string{
"",
"0123456789",
"Hello World!",
"你好",
}

for _, test := range tests {
s1 := NewString(test)
s2 := s1.String()

if s2 != test {
t.Error("invalid string:", s2, "!=", test)
}
}
}

func TestNewStringWrap(t *testing.T) {
tests := []string{
"",
"0123456789",
"Hello World!",
"你好",
}

for _, test := range tests {
s1 := CFStringCreate(test)
s2 := NewStringWrap(s1)

if s2.Ref() != s1 {
t.Error("invalid string ref:", s1, "!=", s2)
}
}
}

func TestStringZeroValue(t *testing.T) {
s1 := &String{}
s2 := s1.String()

if s2 != "" {
t.Error("string zero-value produced an invalid Go string:", s2)
}
}

func TestStringRelease(t *testing.T) {
s := NewString("")
s.release()

if s.ref != nil {
t.Error("releasing didn't set the internal string reference to nil")
}
}

0 comments on commit c368e43

Please sign in to comment.