mirror of
https://github.com/crazybber/awesome-patterns.git
synced 2024-11-24 21:46:03 +03:00
# Conflicts: # README.md
This commit is contained in:
commit
3500e141b7
1
.gitignore
vendored
1
.gitignore
vendored
@ -32,3 +32,4 @@ _testmain.go
|
|||||||
|
|
||||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
*.out
|
*.out
|
||||||
|
*.orig
|
||||||
|
96
README.md
96
README.md
@ -15,96 +15,96 @@ A curated collection of idiomatic design & application patterns for Go language.
|
|||||||
|
|
||||||
| Pattern | Description | Status |
|
| Pattern | Description | Status |
|
||||||
|:-------:|:----------- |:------:|
|
|:-------:|:----------- |:------:|
|
||||||
| [Abstract Factory](/creational/abstract_factory.md) | Provides an interface for creating families of releated objects | ✘ |
|
| [Abstract Factory](/creational/abstract_factory.md) | Provides an interface for creating families of releated objects | âœ|
|
||||||
| [Builder](/creational/builder.md) | Builds a complex object using simple objects | ✔ |
|
| [Builder](/creational/builder.md) | Builds a complex object using simple objects | âœ|
|
||||||
| [Factory Method](/creational/factory.md) | Defers instantiation of an object to a specialized function for creating instances | ✔ |
|
| [Factory Method](/creational/factory.md) | Defers instantiation of an object to a specialized function for creating instances | âœ|
|
||||||
| [Object Pool](/creational/object-pool.md) | Instantiates and maintains a group of objects instances of the same type | ✔ |
|
| [Object Pool](/creational/object-pool.md) | Instantiates and maintains a group of objects instances of the same type | âœ|
|
||||||
| [Singleton](/creational/singleton.md) | Restricts instantiation of a type to one object | ✔ |
|
| [Singleton](/creational/singleton.md) | Restricts instantiation of a type to one object | âœ|
|
||||||
|
|
||||||
## Structural Patterns
|
## Structural Patterns
|
||||||
|
|
||||||
| Pattern | Description | Status |
|
| Pattern | Description | Status |
|
||||||
|:-------:|:----------- |:------:|
|
|:-------:|:----------- |:------:|
|
||||||
| [Bridge](/structural/bridge/main.go) | Decouples an interface from its implementation so that the two can vary independently | ✔ |
|
| [Bridge](/structural/bridge/main.go) | Decouples an interface from its implementation so that the two can vary independently | âœ|
|
||||||
| [Composite](/structural/composite/main.go) | Encapsulates and provides access to a number of different objects | ✔ |
|
| [Composite](/structural/composite/main.go) | Encapsulates and provides access to a number of different objects | âœ|
|
||||||
| [Decorator](/structural/decorator.md) | Adds behavior to an object, statically or dynamically | ✔ |
|
| [Decorator](/structural/decorator.md) | Adds behavior to an object, statically or dynamically | âœ|
|
||||||
| [Facade](/structural/facade/main.go) | Uses one type as an API to a number of others | ✔ |
|
| [Facade](/structural/facade/main.go) | Uses one type as an API to a number of others | âœ|
|
||||||
| [Flyweight](/structural/flyweight/main.go) | Reuses existing instances of objects with similar/identical state to minimize resource usage | ✔ |
|
| [Flyweight](/structural/flyweight/main.go) | Reuses existing instances of objects with similar/identical state to minimize resource usage | âœ|
|
||||||
| [Proxy](/structural/proxy.md) | Provides a surrogate for an object to control it's actions | ✔ |
|
| [Proxy](/structural/proxy.md) | Provides a surrogate for an object to control it's actions | âœ|
|
||||||
|
|
||||||
## Behavioral Patterns
|
## Behavioral Patterns
|
||||||
|
|
||||||
| Pattern | Description | Status |
|
| Pattern | Description | Status |
|
||||||
|:-------:|:----------- |:------:|
|
|:-------:|:----------- |:------:|
|
||||||
| [Chain of Responsibility](/behavioral/chain_of_responsibility/main.go) | Avoids coupling a sender to receiver by giving more than object a chance to handle the request | ✔ |
|
| [Chain of Responsibility](/behavioral/chain_of_responsibility/main.go) | Avoids coupling a sender to receiver by giving more than object a chance to handle the request | âœ|
|
||||||
| [Command](/behavioral/command/main.go) | Bundles a command and arguments to call later | ✔ |
|
| [Command](/behavioral/command/main.go) | Bundles a command and arguments to call later | âœ|
|
||||||
| [Mediator](/behavioral/mediator/main.go) | Connects objects and acts as a proxy | ✔ |
|
| [Mediator](/behavioral/mediator/main.go) | Connects objects and acts as a proxy | âœ|
|
||||||
| [Memento](/behavioral/memento/main.go) | Generate an opaque token that can be used to go back to a previous state | ✔ |
|
| [Memento](/behavioral/memento/main.go) | Generate an opaque token that can be used to go back to a previous state | âœ|
|
||||||
| [Observer](/behavioral/observer.md) | Provide a callback for notification of events/changes to data | ✔ |
|
| [Observer](/behavioral/observer.md) | Provide a callback for notification of events/changes to data | âœ|
|
||||||
| [Registry](/behavioral/registry.md) | Keep track of all subclasses of a given class | ✘ |
|
| [Registry](/behavioral/registry.md) | Keep track of all subclasses of a given class | âœ|
|
||||||
| [State](/behavioral/state/main.go) | Encapsulates varying behavior for the same object based on its internal state | ✔ |
|
| [State](/behavioral/state/main.go) | Encapsulates varying behavior for the same object based on its internal state | âœ|
|
||||||
| [Strategy](/behavioral/strategy.md) | Enables an algorithm's behavior to be selected at runtime | ✔ |
|
| [Strategy](/behavioral/strategy.md) | Enables an algorithm's behavior to be selected at runtime | âœ|
|
||||||
| [Template](/behavioral/template/main.go) | Defines a skeleton class which defers some methods to subclasses | ✔ |
|
| [Template](/behavioral/template/main.go) | Defines a skeleton class which defers some methods to subclasses | âœ|
|
||||||
| [Visitor](/behavioral/visitor/main.go) | Separates an algorithm from an object on which it operates | ✔ |
|
| [Visitor](/behavioral/visitor/main.go) | Separates an algorithm from an object on which it operates | âœ|
|
||||||
|
|
||||||
## Synchronization Patterns
|
## Synchronization Patterns
|
||||||
|
|
||||||
| Pattern | Description | Status |
|
| Pattern | Description | Status |
|
||||||
|:-------:|:----------- |:------:|
|
|:-------:|:----------- |:------:|
|
||||||
| [Condition Variable](/synchronization/condition_variable.md) | Provides a mechanism for threads to temporarily give up access in order to wait for some condition | ✘ |
|
| [Condition Variable](/synchronization/condition_variable.md) | Provides a mechanism for threads to temporarily give up access in order to wait for some condition | âœ|
|
||||||
| [Lock/Mutex](/synchronization/mutex.md) | Enforces mutual exclusion limit on a resource to gain exclusive access | ✘ |
|
| [Lock/Mutex](/synchronization/mutex.md) | Enforces mutual exclusion limit on a resource to gain exclusive access | âœ|
|
||||||
| [Monitor](/synchronization/monitor.md) | Combination of mutex and condition variable patterns | ✘ |
|
| [Monitor](/synchronization/monitor.md) | Combination of mutex and condition variable patterns | âœ|
|
||||||
| [Read-Write Lock](/synchronization/read_write_lock.md) | Allows parallel read access, but only exclusive access on write operations to a resource | ✘ |
|
| [Read-Write Lock](/synchronization/read_write_lock.md) | Allows parallel read access, but only exclusive access on write operations to a resource | âœ|
|
||||||
| [Semaphore](/synchronization/semaphore.md) | Allows controlling access to a common resource | ✔ |
|
| [Semaphore](/synchronization/semaphore.md) | Allows controlling access to a common resource | âœ|
|
||||||
|
|
||||||
## Concurrency Patterns
|
## Concurrency Patterns
|
||||||
|
|
||||||
| Pattern | Description | Status |
|
| Pattern | Description | Status |
|
||||||
|:-------:|:----------- |:------:|
|
|:-------:|:----------- |:------:|
|
||||||
| [N-Barrier](/concurrency/n_barrier/main.go) | Prevents a process from proceeding until all N processes reach to the barrier | ✔ |
|
| [N-Barrier](/concurrency/n_barrier/main.go) | Prevents a process from proceeding until all N processes reach to the barrier | âœ|
|
||||||
| [Bounded Parallelism](/concurrency/bounded_parallelism.md) | Completes large number of independent tasks with resource limits | ✔ |
|
| [Bounded Parallelism](/concurrency/bounded/bounded_parallelism.md) | Completes large number of independent tasks with resource limits | âœ|
|
||||||
| [Broadcast](/concurrency/broadcast.md) | Transfers a message to all recipients simultaneously | ✘ |
|
| [Broadcast](/concurrency/broadcast.md) | Transfers a message to all recipients simultaneously | âœ|
|
||||||
| [Coroutines](/concurrency/coroutine.md) | Subroutines that allow suspending and resuming execution at certain locations | ✘ |
|
| [Coroutines](/concurrency/coroutine.md) | Subroutines that allow suspending and resuming execution at certain locations | âœ|
|
||||||
| [Generators](/concurrency/generator.md) | Yields a sequence of values one at a time | ✔ |
|
| [Generators](/concurrency/generator.md) | Yields a sequence of values one at a time | âœ|
|
||||||
| [Reactor](/concurrency/reactor.md) | Demultiplexes service requests delivered concurrently to a service handler and dispatches them syncronously to the associated request handlers | ✘ |
|
| [Reactor](/concurrency/reactor.md) | Demultiplexes service requests delivered concurrently to a service handler and dispatches them syncronously to the associated request handlers | âœ|
|
||||||
| [Parallelism](/concurrency/parallelism.md) | Completes large number of independent tasks | ✔ |
|
| [Parallelism](/concurrency/parallelism.md) | Completes large number of independent tasks | âœ|
|
||||||
| [Producer Consumer](/concurrency/producer_consumer.md) | Separates tasks from task executions | ✘ |
|
| [Producer Consumer](/concurrency/producer_consumer.md) | Separates tasks from task executions | âœ|
|
||||||
|
|
||||||
## Messaging Patterns
|
## Messaging Patterns
|
||||||
|
|
||||||
| Pattern | Description | Status |
|
| Pattern | Description | Status |
|
||||||
|:-------:|:----------- |:------:|
|
|:-------:|:----------- |:------:|
|
||||||
| [Fan-In](/messaging/fan_in.md) | Funnels tasks to a work sink (e.g. server) | ✔ |
|
| [Fan-In](/messaging/fan_in.md) | Funnels tasks to a work sink (e.g. server) | âœ|
|
||||||
| [Fan-Out](/messaging/fan_out.md) | Distributes tasks among workers (e.g. producer) | ✔ |
|
| [Fan-Out](/messaging/fan_out.md) | Distributes tasks among workers (e.g. producer) | âœ|
|
||||||
| [Futures & Promises](/messaging/futures_promises.md) | Acts as a place-holder of a result that is initially unknown for synchronization purposes | ✘ |
|
| [Futures & Promises](/messaging/futures_promises.md) | Acts as a place-holder of a result that is initially unknown for synchronization purposes | âœ|
|
||||||
| [Publish/Subscribe](/messaging/publish_subscribe.md) | Passes information to a collection of recipients who subscribed to a topic | ✔ |
|
| [Publish/Subscribe](/messaging/publish_subscribe.md) | Passes information to a collection of recipients who subscribed to a topic | âœ|
|
||||||
| [Push & Pull](/messaging/push_pull.md) | Distributes messages to multiple workers, arranged in a pipeline | ✘ |
|
| [Push & Pull](/messaging/push_pull.md) | Distributes messages to multiple workers, arranged in a pipeline | âœ|
|
||||||
|
|
||||||
## Stability Patterns
|
## Stability Patterns
|
||||||
|
|
||||||
| Pattern | Description | Status |
|
| Pattern | Description | Status |
|
||||||
|:-------:|:----------- |:------:|
|
|:-------:|:----------- |:------:|
|
||||||
| [Bulkheads](/stability/bulkhead.md) | Enforces a principle of failure containment (i.e. prevents cascading failures) | ✘ |
|
| [Bulkheads](/stability/bulkhead.md) | Enforces a principle of failure containment (i.e. prevents cascading failures) | âœ|
|
||||||
| [Circuit-Breaker](/stability/circuit-breaker.md) | Stops the flow of the requests when requests are likely to fail | ✔ |
|
| [Circuit-Breaker](/stability/circuit-breaker.md) | Stops the flow of the requests when requests are likely to fail | âœ|
|
||||||
| [Deadline](/stability/deadline.md) | Allows clients to stop waiting for a response once the probability of response becomes low (e.g. after waiting 10 seconds for a page refresh) | ✘ |
|
| [Deadline](/stability/deadline.md) | Allows clients to stop waiting for a response once the probability of response becomes low (e.g. after waiting 10 seconds for a page refresh) | âœ|
|
||||||
| [Fail-Fast](/stability/fail_fast.md) | Checks the availability of required resources at the start of a request and fails if the requirements are not satisfied | ✘ |
|
| [Fail-Fast](/stability/fail_fast.md) | Checks the availability of required resources at the start of a request and fails if the requirements are not satisfied | âœ|
|
||||||
| [Handshaking](/stability/handshaking.md) | Asks a component if it can take any more load, if it can't, the request is declined | ✘ |
|
| [Handshaking](/stability/handshaking.md) | Asks a component if it can take any more load, if it can't, the request is declined | âœ|
|
||||||
| [Steady-State](/stability/steady_state.md) | For every service that accumulates a resource, some other service must recycle that resource | ✘ |
|
| [Steady-State](/stability/steady_state.md) | For every service that accumulates a resource, some other service must recycle that resource | âœ|
|
||||||
|
|
||||||
## Profiling Patterns
|
## Profiling Patterns
|
||||||
|
|
||||||
| Pattern | Description | Status |
|
| Pattern | Description | Status |
|
||||||
|:-------:|:----------- |:------:|
|
|:-------:|:----------- |:------:|
|
||||||
| [Timing Functions](/profiling/timing.md) | Wraps a function and logs the execution | ✔ |
|
| [Timing Functions](/profiling/timing.md) | Wraps a function and logs the execution | âœ|
|
||||||
|
|
||||||
## Idioms
|
## Idioms
|
||||||
|
|
||||||
| Pattern | Description | Status |
|
| Pattern | Description | Status |
|
||||||
|:-------:|:----------- |:------:|
|
|:-------:|:----------- |:------:|
|
||||||
| [Functional Options](/idiom/functional-options.md) | Allows creating clean APIs with sane defaults and idiomatic overrides | ✔ |
|
| [Functional Options](/idiom/functional-options.md) | Allows creating clean APIs with sane defaults and idiomatic overrides | âœ|
|
||||||
|
|
||||||
## Anti-Patterns
|
## Anti-Patterns
|
||||||
|
|
||||||
| Pattern | Description | Status |
|
| Pattern | Description | Status |
|
||||||
|:-------:|:----------- |:------:|
|
|:-------:|:----------- |:------:|
|
||||||
| [Cascading Failures](/anti-patterns/cascading_failures.md) | A failure in a system of interconnected parts in which the failure of a part causes a domino effect | ✘ |
|
| [Cascading Failures](/anti-patterns/cascading_failures.md) | A failure in a system of interconnected parts in which the failure of a part causes a domino effect | âœ|
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
* [Semaphore](/synchronization/semaphore.md)
|
* [Semaphore](/synchronization/semaphore.md)
|
||||||
* [Concurrency Patterns](/README.md#concurrency-patterns)
|
* [Concurrency Patterns](/README.md#concurrency-patterns)
|
||||||
* [N-Barrier](/concurrency/barrier.md)
|
* [N-Barrier](/concurrency/barrier.md)
|
||||||
* [Bounded Parallelism](/concurrency/bounded_parallelism.md)
|
* [Bounded Parallelism](/concurrency/bounded/bounded_parallelism.md)
|
||||||
* [Broadcast](/concurrency/broadcast.md)
|
* [Broadcast](/concurrency/broadcast.md)
|
||||||
* [Coroutines](/concurrency/coroutine.md)
|
* [Coroutines](/concurrency/coroutine.md)
|
||||||
* [Generators](/concurrency/generator.md)
|
* [Generators](/concurrency/generator.md)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# Bounded Parallelism Pattern
|
# Bounded Parallelism Pattern
|
||||||
|
|
||||||
[Bounded parallelism](https://blog.golang.org/pipelines#TOC_9.) is similar to [parallelism](parallelism.md), but allows limits to be placed on allocation.
|
[Bounded parallelism](https://blog.golang.org/pipelines#TOC_9.) is similar to [parallelism](../parallelism.md), but allows limits to be placed on allocation.
|
||||||
|
|
||||||
# Implementation and Example
|
# Implementation and Example
|
||||||
|
|
40
playground/basic/address_test.go
Normal file
40
playground/basic/address_test.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package basic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPrintAddress(t *testing.T) {
|
||||||
|
var a int
|
||||||
|
fmt.Printf("%T, %v, %p \n", a, a, &a)
|
||||||
|
passByVariable(a)
|
||||||
|
passByPointer(&a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func passByVariable(a int) {
|
||||||
|
fmt.Printf("%T, %v, %p \n", a, a, &a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func passByPointer(a *int) {
|
||||||
|
fmt.Printf("%T, %v, %p \n", a, a, &a)
|
||||||
|
fmt.Printf("%T, %v, %p \n", *a, *a, &*a)
|
||||||
|
}
|
||||||
|
|
||||||
|
type robot struct{}
|
||||||
|
|
||||||
|
func TestStructAddress(t *testing.T) {
|
||||||
|
var a robot
|
||||||
|
fmt.Printf("%T, %v, %p \n", a, a, &a)
|
||||||
|
passStructByVariable(a)
|
||||||
|
passStructByPointer(&a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func passStructByVariable(a robot) {
|
||||||
|
fmt.Printf("[passStructByVariable] %T, %v, %p \n", a, a, &a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func passStructByPointer(a *robot) {
|
||||||
|
fmt.Printf("[passStructByPointer] %T, %v, %p \n", a, a, &a)
|
||||||
|
fmt.Printf("[passStructByPointer] %T, %v, %p \n", *a, *a, &*a)
|
||||||
|
}
|
BIN
playground/cbor/2.png
Normal file
BIN
playground/cbor/2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 MiB |
53
playground/cbor/cbor2_test.go
Normal file
53
playground/cbor/cbor2_test.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package cbor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/2tvenom/cbor"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Image struct {
|
||||||
|
Name string
|
||||||
|
Content []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCborEncode2(t *testing.T) {
|
||||||
|
// Read origin file
|
||||||
|
b := new(bytes.Buffer)
|
||||||
|
err := getImageBytes("./on.png", b)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
origin := b.Bytes()
|
||||||
|
|
||||||
|
//image := &Image{Name:"on",Content:origin}
|
||||||
|
|
||||||
|
// Encode
|
||||||
|
fmt.Println("--------- Encode ---------")
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
encoder := cbor.NewEncoder(&buf)
|
||||||
|
ok, error := encoder.Marshal(origin)
|
||||||
|
|
||||||
|
//check binary string
|
||||||
|
if !ok {
|
||||||
|
fmt.Errorf("Error decoding %s", error)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Size: ", len(buf.Bytes()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode
|
||||||
|
//fmt.Println("--------- Decode ---------",buf.Bytes())
|
||||||
|
//var img []byte
|
||||||
|
//ok, err = encoder.Unmarshal(buf.Bytes(), &img)
|
||||||
|
//if !ok {
|
||||||
|
// fmt.Printf("Error Unmarshal %s", err)
|
||||||
|
// return
|
||||||
|
//}
|
||||||
|
////output
|
||||||
|
//fmt.Printf("%v", img)
|
||||||
|
|
||||||
|
}
|
48
playground/cbor/cbor3_test.go
Normal file
48
playground/cbor/cbor3_test.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package cbor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"go.mozilla.org/cose"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCborEncode3(t *testing.T) {
|
||||||
|
// Read origin file
|
||||||
|
b := new(bytes.Buffer)
|
||||||
|
err := getImageBytes("./on.png", b)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
origin := b.Bytes()
|
||||||
|
|
||||||
|
//image := &Image{Name:"on",Content:origin}
|
||||||
|
fmt.Println("Size: ", len(origin))
|
||||||
|
// Encode
|
||||||
|
fmt.Println("--------- Encode ---------")
|
||||||
|
|
||||||
|
encoded, error := cose.Marshal(origin)
|
||||||
|
|
||||||
|
if error != nil {
|
||||||
|
fmt.Errorf("Error decoding %s", error)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Size: ", len(encoded))
|
||||||
|
//fmt.Println("Content: ",string(encoded))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode
|
||||||
|
fmt.Println("--------- Decode ---------")
|
||||||
|
//var img Image
|
||||||
|
unmarshal, err := cose.Unmarshal(encoded)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Error Unmarshal %s", err)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
fmt.Println("Size: ", len(unmarshal.([]byte)))
|
||||||
|
//fmt.Println("Content: ",unmarshal.([]byte))
|
||||||
|
}
|
||||||
|
writeToFile("3", unmarshal.([]byte))
|
||||||
|
|
||||||
|
}
|
104
playground/cbor/cbor_test.go
Normal file
104
playground/cbor/cbor_test.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package cbor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/jpeg"
|
||||||
|
"image/png"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ugorji/go/codec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCborEncode(t *testing.T) {
|
||||||
|
// Read origin file
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
err := getImageBytes("./on.png", buf)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
origin := buf.Bytes()
|
||||||
|
|
||||||
|
fmt.Println("size:", len(origin))
|
||||||
|
writeToFile("1", origin)
|
||||||
|
|
||||||
|
// Encode
|
||||||
|
encoded, err := encodeBinaryValue(buf.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("size:", len(encoded))
|
||||||
|
writeToFile("2", encoded)
|
||||||
|
|
||||||
|
// Decode
|
||||||
|
decoded, err := decodeBinaryValue(encoded)
|
||||||
|
fmt.Println("size:", len(decoded))
|
||||||
|
writeToFile("3", decoded)
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeBinaryValue(b []byte) ([]byte, error) {
|
||||||
|
var ch codec.CborHandle
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
|
||||||
|
enc := codec.NewEncoder(buf, &ch)
|
||||||
|
err := enc.Encode(&b)
|
||||||
|
|
||||||
|
return buf.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func decodeBinaryValue(b []byte) ([]byte, error) {
|
||||||
|
var ch codec.CborHandle
|
||||||
|
var decoded []byte
|
||||||
|
var bufReader = bufio.NewReader(bytes.NewReader(b))
|
||||||
|
var dec = codec.NewDecoder(bufReader, &ch)
|
||||||
|
var err = dec.Decode(&decoded)
|
||||||
|
return decoded, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func getImageBytes(imgFile string, buf *bytes.Buffer) error {
|
||||||
|
// Read existing image from file
|
||||||
|
img, err := os.Open(imgFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer img.Close()
|
||||||
|
|
||||||
|
// TODO: Attach MediaType property, determine if decoding
|
||||||
|
// early is required (to optimize edge processing)
|
||||||
|
|
||||||
|
// Expect "png" or "jpeg" image type
|
||||||
|
imageData, imageType, err := image.Decode(img)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Finished with file. Reset file pointer
|
||||||
|
img.Seek(0, 0)
|
||||||
|
if imageType == "jpeg" {
|
||||||
|
err = jpeg.Encode(buf, imageData, nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if imageType == "png" {
|
||||||
|
err = png.Encode(buf, imageData)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeToFile(fileName string, b []byte) {
|
||||||
|
f, _ := os.Create(fileName)
|
||||||
|
n2, err := f.Write(b)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Printf("wrote file %d bytes\n", n2)
|
||||||
|
}
|
BIN
playground/cbor/on.png
Normal file
BIN
playground/cbor/on.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
17
playground/codecoverage/size.go
Normal file
17
playground/codecoverage/size.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package codecoverage
|
||||||
|
|
||||||
|
func Size(a int) string {
|
||||||
|
switch {
|
||||||
|
case a < 0:
|
||||||
|
return "negative"
|
||||||
|
case a == 0:
|
||||||
|
return "zero"
|
||||||
|
case a < 10:
|
||||||
|
return "small"
|
||||||
|
case a < 100:
|
||||||
|
return "big"
|
||||||
|
case a < 1000:
|
||||||
|
return "huge"
|
||||||
|
}
|
||||||
|
return "enormous"
|
||||||
|
}
|
26
playground/codecoverage/size_test.go
Normal file
26
playground/codecoverage/size_test.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package codecoverage
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
type Test struct {
|
||||||
|
in int
|
||||||
|
out string
|
||||||
|
}
|
||||||
|
|
||||||
|
var tests = []Test{
|
||||||
|
{-1, "negative"},
|
||||||
|
{0, "zero"},
|
||||||
|
{5, "small"},
|
||||||
|
{99, "big"},
|
||||||
|
{100, "huge"},
|
||||||
|
{10001, "enormous"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSize(t *testing.T) {
|
||||||
|
for i, test := range tests {
|
||||||
|
size := Size(test.in)
|
||||||
|
if size != test.out {
|
||||||
|
t.Errorf("#%d: Size(%d)=%s; want %s", i, test.in, size, test.out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
86
playground/cron/cron_test.go
Normal file
86
playground/cron/cron_test.go
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
package cron
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/edgexfoundry/edgex-go/pkg/models"
|
||||||
|
"github.com/robfig/cron"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Job struct {
|
||||||
|
schedule models.Schedule
|
||||||
|
scheduleEvents []models.ScheduleEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (job Job) Run() {
|
||||||
|
fmt.Println(job.schedule.Name, job.schedule.Frequency)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCronWithAddJob(t *testing.T) {
|
||||||
|
var job = Job{
|
||||||
|
schedule: models.Schedule{
|
||||||
|
Id: "xxx",
|
||||||
|
Name: "5sec-schedule",
|
||||||
|
Frequency: "PT5S",
|
||||||
|
},
|
||||||
|
scheduleEvents: []models.ScheduleEvent{},
|
||||||
|
}
|
||||||
|
var job2 = Job{
|
||||||
|
schedule: models.Schedule{
|
||||||
|
Id: "xxx",
|
||||||
|
Name: "2sec-schedule",
|
||||||
|
Frequency: "PT2S",
|
||||||
|
},
|
||||||
|
scheduleEvents: []models.ScheduleEvent{},
|
||||||
|
}
|
||||||
|
|
||||||
|
// init cron
|
||||||
|
c := cron.New()
|
||||||
|
|
||||||
|
// add cron job
|
||||||
|
var spec = fmt.Sprintf("@every %v", ParseDuration(job.schedule.Frequency))
|
||||||
|
c.AddJob(spec, job)
|
||||||
|
|
||||||
|
spec = fmt.Sprintf("@every %v", ParseDuration(job2.schedule.Frequency))
|
||||||
|
c.AddJob(spec, job2)
|
||||||
|
|
||||||
|
// start cron
|
||||||
|
c.Start()
|
||||||
|
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
// keep alive
|
||||||
|
//select {}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCronWithAddFunc(t *testing.T) {
|
||||||
|
// init cron
|
||||||
|
c := cron.New()
|
||||||
|
|
||||||
|
// add cron job
|
||||||
|
var duration = ParseDuration("PT2S")
|
||||||
|
var spec = fmt.Sprintf("@every %v", duration)
|
||||||
|
|
||||||
|
c.AddFunc(spec, func() {
|
||||||
|
// @every 2s
|
||||||
|
fmt.Println(spec)
|
||||||
|
})
|
||||||
|
|
||||||
|
// start cron
|
||||||
|
c.Start()
|
||||||
|
|
||||||
|
// keep alive
|
||||||
|
select {}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseISO8601(t *testing.T) {
|
||||||
|
var duration = ParseDuration("PT2S")
|
||||||
|
|
||||||
|
// PT2S -> 2s
|
||||||
|
fmt.Println(duration)
|
||||||
|
// PT15M -> 15m0s
|
||||||
|
fmt.Println(ParseDuration("PT15M"))
|
||||||
|
// P12Y4MT15M -> 108000h15m0s
|
||||||
|
fmt.Println(ParseDuration("P12Y4MT15M"))
|
||||||
|
}
|
35
playground/cron/iso8601parser.go
Normal file
35
playground/cron/iso8601parser.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package cron
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ParseDuration(str string) time.Duration {
|
||||||
|
durationRegex := regexp.MustCompile(`P(?P<years>\d+Y)?(?P<months>\d+M)?(?P<days>\d+D)?T?(?P<hours>\d+H)?(?P<minutes>\d+M)?(?P<seconds>\d+S)?`)
|
||||||
|
matches := durationRegex.FindStringSubmatch(str)
|
||||||
|
|
||||||
|
years := ParseInt64(matches[1])
|
||||||
|
months := ParseInt64(matches[2])
|
||||||
|
days := ParseInt64(matches[3])
|
||||||
|
hours := ParseInt64(matches[4])
|
||||||
|
minutes := ParseInt64(matches[5])
|
||||||
|
seconds := ParseInt64(matches[6])
|
||||||
|
|
||||||
|
hour := int64(time.Hour)
|
||||||
|
minute := int64(time.Minute)
|
||||||
|
second := int64(time.Second)
|
||||||
|
return time.Duration(years*24*365*hour + months*30*24*hour + days*24*hour + hours*hour + minutes*minute + seconds*second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseInt64(value string) int64 {
|
||||||
|
if len(value) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
parsed, err := strconv.Atoi(value[:len(value)-1])
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return int64(parsed)
|
||||||
|
}
|
14
playground/factory/robot.go
Normal file
14
playground/factory/robot.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package factory
|
||||||
|
|
||||||
|
import "log"
|
||||||
|
|
||||||
|
var speakFuncs = make(map[string]interface{})
|
||||||
|
|
||||||
|
func say(funcName string) {
|
||||||
|
speakFunc, ok := speakFuncs[funcName]
|
||||||
|
if !ok {
|
||||||
|
log.Println("speakFunc not exist")
|
||||||
|
} else {
|
||||||
|
speakFunc.(func())()
|
||||||
|
}
|
||||||
|
}
|
8
playground/factory/robot_test.go
Normal file
8
playground/factory/robot_test.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package factory
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestSay(t *testing.T) {
|
||||||
|
say("xxx")
|
||||||
|
say("hi")
|
||||||
|
}
|
16
playground/factory/robotfuncs.go
Normal file
16
playground/factory/robotfuncs.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package factory
|
||||||
|
|
||||||
|
import "log"
|
||||||
|
|
||||||
|
func sayHi() {
|
||||||
|
log.Print("Hi~")
|
||||||
|
}
|
||||||
|
|
||||||
|
func sayHello() {
|
||||||
|
log.Print("Hello~")
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
speakFuncs["hi"] = sayHi
|
||||||
|
speakFuncs["hello"] = sayHello
|
||||||
|
}
|
24
playground/goroutine/basic_chan_test.go
Normal file
24
playground/goroutine/basic_chan_test.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package goroutine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFiveGopherWithChan(t *testing.T) {
|
||||||
|
c := make(chan int)
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
go sleepyGopherWithChan(i, c)
|
||||||
|
}
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
gopherID := <-c
|
||||||
|
fmt.Println("gopher ", gopherID, " has finished sleeping")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sleepyGopherWithChan(id int, c chan int) {
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
fmt.Println("... ", id, " snore ...")
|
||||||
|
c <- id
|
||||||
|
}
|
25
playground/goroutine/basic_test.go
Normal file
25
playground/goroutine/basic_test.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package goroutine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestOneGopher(t *testing.T) {
|
||||||
|
go sleepyGopher(1)
|
||||||
|
time.Sleep(3 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFiveGopher(t *testing.T) {
|
||||||
|
c := make(chan int)
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
go sleepyGopherWithChan(i, c)
|
||||||
|
}
|
||||||
|
time.Sleep(3 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sleepyGopher(id int) {
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
fmt.Println("... ", id, " snore ...")
|
||||||
|
}
|
32
playground/goroutine/basic_waitgroup_test.go
Normal file
32
playground/goroutine/basic_waitgroup_test.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package goroutine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWaitGophers(t *testing.T) {
|
||||||
|
var gophers = []string{"tom", "peter", "john", "brown"}
|
||||||
|
|
||||||
|
var waitGroup sync.WaitGroup
|
||||||
|
waitGroup.Add(len(gophers))
|
||||||
|
|
||||||
|
for i := 0; i < len(gophers); i++ {
|
||||||
|
go func(wg *sync.WaitGroup, name string) {
|
||||||
|
sleepyGopherSnore(name)
|
||||||
|
wg.Done()
|
||||||
|
}(&waitGroup, gophers[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
waitGroup.Wait()
|
||||||
|
|
||||||
|
fmt.Println("All done")
|
||||||
|
}
|
||||||
|
|
||||||
|
func sleepyGopherSnore(name string) {
|
||||||
|
fmt.Println(name, ": ... start snore")
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
fmt.Println(name, ": ... snore")
|
||||||
|
}
|
11
playground/goroutine/deadlock_test.go
Normal file
11
playground/goroutine/deadlock_test.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package goroutine
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
// A deadlock happens when a group of goroutines are waiting for each other and none of them is able to proceed.
|
||||||
|
// The program will get stuck on the channel send operation waiting forever for someone to read the value.
|
||||||
|
// Go is able to detect situations like this at runtime.
|
||||||
|
func TestDeadlock(t *testing.T) {
|
||||||
|
c := make(chan int)
|
||||||
|
<-c
|
||||||
|
}
|
39
playground/goroutine/pipeline_test.go
Normal file
39
playground/goroutine/pipeline_test.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package goroutine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func sourceGopher(downstream chan string) {
|
||||||
|
for _, v := range []string{"hello world", "a bad apple", "goodbye all"} {
|
||||||
|
downstream <- v
|
||||||
|
}
|
||||||
|
close(downstream)
|
||||||
|
}
|
||||||
|
|
||||||
|
func filterGopher(upstream, downstream chan string) {
|
||||||
|
for item := range upstream {
|
||||||
|
fmt.Println("filter ", item)
|
||||||
|
|
||||||
|
if !strings.Contains(item, "bad") {
|
||||||
|
downstream <- item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func printGopher(upstream chan string) {
|
||||||
|
for item := range upstream {
|
||||||
|
fmt.Println("print ", item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pipeline source->filter->print
|
||||||
|
func TestPipeline(t *testing.T) {
|
||||||
|
c0 := make(chan string)
|
||||||
|
c1 := make(chan string)
|
||||||
|
go sourceGopher(c0)
|
||||||
|
go filterGopher(c0, c1)
|
||||||
|
printGopher(c1)
|
||||||
|
}
|
48
playground/http/get_test.go
Normal file
48
playground/http/get_test.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGet(t *testing.T) {
|
||||||
|
counts := 2
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(counts)
|
||||||
|
|
||||||
|
for i := 0; i < counts; i++ {
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
getValue()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getValue() {
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
x := rand.Intn(10)
|
||||||
|
var url string
|
||||||
|
if x > 5 {
|
||||||
|
url = "http://localhost:48082/api/v1/device/5bae2ef4f37ba14693a5e4fc/command/5bae2ef4f37ba14693a5e4eb"
|
||||||
|
} else {
|
||||||
|
url = "http://localhost:48082/api/v1/device/5bae2d1bf37ba14693a5e4e9/command/5bae2d05f37ba14693a5e4e2"
|
||||||
|
}
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(string(resBody))
|
||||||
|
}
|
46
playground/http/postyamlstring_test.go
Normal file
46
playground/http/postyamlstring_test.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPostYamlString(t *testing.T) {
|
||||||
|
var filePath = "/Users/bruce/Desktop/HVAC-CoolMasterNet.yml"
|
||||||
|
var url = "http://localhost:48081/api/v1/deviceprofile/upload"
|
||||||
|
|
||||||
|
// read file to byte
|
||||||
|
yamlFile, err := ioutil.ReadFile(filePath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(yamlFile))
|
||||||
|
|
||||||
|
// create http post request
|
||||||
|
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(yamlFile))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// submit request
|
||||||
|
client := &http.Client{}
|
||||||
|
res, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check response
|
||||||
|
fmt.Println("== upload finish ==")
|
||||||
|
resBody, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(res.StatusCode)
|
||||||
|
fmt.Println(res.Header)
|
||||||
|
res.Body.Close()
|
||||||
|
fmt.Println(string(resBody))
|
||||||
|
}
|
63
playground/http/upload_test.go
Normal file
63
playground/http/upload_test.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUploadFormFile(t *testing.T) {
|
||||||
|
var filePath = "/Users/bruce/Desktop/HVAC-CoolMasterNet.yml"
|
||||||
|
var url = "http://localhost:48081/api/v1/deviceprofile/uploadfile"
|
||||||
|
|
||||||
|
// Retch file
|
||||||
|
fmt.Println("Read file: ", filepath.Base(filePath))
|
||||||
|
yamlFile, err := ioutil.ReadFile(filePath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create form data
|
||||||
|
body := new(bytes.Buffer)
|
||||||
|
//body := &bytes.Buffer{}
|
||||||
|
writer := multipart.NewWriter(body)
|
||||||
|
formFileWriter, err := writer.CreateFormFile("file", filepath.Base(filePath))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = io.Copy(formFileWriter, bytes.NewReader(yamlFile))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
writer.Close()
|
||||||
|
|
||||||
|
// create http post request
|
||||||
|
req, err := http.NewRequest(http.MethodPost, url, body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||||
|
|
||||||
|
// submit request
|
||||||
|
client := &http.Client{}
|
||||||
|
res, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check response
|
||||||
|
fmt.Println("== upload finish ==")
|
||||||
|
resBody, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(res.StatusCode)
|
||||||
|
fmt.Println(res.Header)
|
||||||
|
res.Body.Close()
|
||||||
|
fmt.Println(string(resBody))
|
||||||
|
}
|
15
playground/mocklib/mocks/Robot.go
Normal file
15
playground/mocklib/mocks/Robot.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// Code generated by mockery v1.0.0. DO NOT EDIT.
|
||||||
|
|
||||||
|
package mocks
|
||||||
|
|
||||||
|
import mock "github.com/stretchr/testify/mock"
|
||||||
|
|
||||||
|
// Robot is an autogenerated mock type for the Robot type
|
||||||
|
type Robot struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// SayHi provides a mock function with given fields:
|
||||||
|
func (_m *Robot) SayHi() {
|
||||||
|
_m.Called()
|
||||||
|
}
|
45
playground/mocklib/robot.go
Normal file
45
playground/mocklib/robot.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package mocklib
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// Robot
|
||||||
|
type Robot interface {
|
||||||
|
SayHi()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceRobot is kind of Robot can offer services
|
||||||
|
type ServiceRobot struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (robot *ServiceRobot) SayHi() {
|
||||||
|
fmt.Println("Hi, I'm service robot")
|
||||||
|
}
|
||||||
|
|
||||||
|
// IndustrialRobot is kind of Robot can do some jobs
|
||||||
|
type IndustrialRobot struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (robot *IndustrialRobot) SayHi() {
|
||||||
|
fmt.Println("Hi, I'm industrial robot")
|
||||||
|
}
|
||||||
|
|
||||||
|
func StartRobots() {
|
||||||
|
robots := initializeRobots()
|
||||||
|
makeRobotsSayHi(robots)
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize all robots
|
||||||
|
func initializeRobots() []Robot {
|
||||||
|
robots := []Robot{
|
||||||
|
&ServiceRobot{},
|
||||||
|
&IndustrialRobot{},
|
||||||
|
}
|
||||||
|
return robots
|
||||||
|
}
|
||||||
|
|
||||||
|
// makeRobotsSayHi is used for making robots say hi
|
||||||
|
func makeRobotsSayHi(robots []Robot) {
|
||||||
|
for _, robot := range robots {
|
||||||
|
robot.SayHi()
|
||||||
|
}
|
||||||
|
}
|
32
playground/mocklib/robot_test.go
Normal file
32
playground/mocklib/robot_test.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package mocklib
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/weichou1229/go-patterns/playground/mocklib/mocks"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestStartRobots(t *testing.T) {
|
||||||
|
StartRobots()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMakeRobotsSayHi(t *testing.T) {
|
||||||
|
// create an instance of our test object
|
||||||
|
mockRobotA := new(mocks.Robot)
|
||||||
|
mockRobotB := new(mocks.Robot)
|
||||||
|
|
||||||
|
// setup expectations
|
||||||
|
mockRobotA.On("SayHi").Return(nil, nil)
|
||||||
|
mockRobotB.On("SayHi").Return(nil, nil)
|
||||||
|
|
||||||
|
robots := []Robot{
|
||||||
|
mockRobotA,
|
||||||
|
mockRobotB,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Act
|
||||||
|
makeRobotsSayHi(robots)
|
||||||
|
|
||||||
|
// Assert that the expectations were met
|
||||||
|
mockRobotA.AssertExpectations(t)
|
||||||
|
mockRobotB.AssertExpectations(t)
|
||||||
|
}
|
10
playground/panic/trypanic.go
Normal file
10
playground/panic/trypanic.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package trypanic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Try() {
|
||||||
|
var test *string
|
||||||
|
fmt.Println(*test)
|
||||||
|
}
|
14
playground/parse/parseInt_test.go
Normal file
14
playground/parse/parseInt_test.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package parse
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseInt(t *testing.T) {
|
||||||
|
var _, err = strconv.ParseInt("127", 0, 8)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
26
playground/pointer/pointer_test.go
Normal file
26
playground/pointer/pointer_test.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package pointer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBasic(t *testing.T) {
|
||||||
|
answer := 42
|
||||||
|
fmt.Println(&answer) // & is address operator
|
||||||
|
|
||||||
|
address := &answer
|
||||||
|
fmt.Println(*address) // * is dereferencing, which providers the value that a memory address refers to.
|
||||||
|
fmt.Printf("address is a %T \n", address) // print the pointer type
|
||||||
|
|
||||||
|
var address2 *int // declare a pointer
|
||||||
|
address2 = address // address2 can store some pinter type
|
||||||
|
fmt.Println(*address2)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPointer(t *testing.T) {
|
||||||
|
var test *string = new(string)
|
||||||
|
*test = "123"
|
||||||
|
fmt.Println(test)
|
||||||
|
}
|
27
playground/singleton/internal/singleton.go
Normal file
27
playground/singleton/internal/singleton.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// singleton is private struct, it should be created and fetched by GetSingletonObject func
|
||||||
|
type singleton struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (singleton) SayHi() {
|
||||||
|
fmt.Println("Hi!")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
once sync.Once
|
||||||
|
instance singleton
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetSingletonObject() singleton {
|
||||||
|
once.Do(func() {
|
||||||
|
instance = singleton{}
|
||||||
|
})
|
||||||
|
|
||||||
|
return instance
|
||||||
|
}
|
10
playground/singleton/main.go
Normal file
10
playground/singleton/main.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/weichou1229/go-patterns/playground/singleton/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var s = internal.GetSingletonObject()
|
||||||
|
s.SayHi()
|
||||||
|
}
|
52
playground/syncmap/syncmap_test.go
Normal file
52
playground/syncmap/syncmap_test.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package syncmap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Order struct {
|
||||||
|
Id int
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSync(t *testing.T) {
|
||||||
|
var waitGroup sync.WaitGroup
|
||||||
|
waitGroup.Add(10)
|
||||||
|
var cache sync.Map
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
go func() {
|
||||||
|
cache.Store("test", &Order{})
|
||||||
|
order, _ := cache.Load("test")
|
||||||
|
o := order.(*Order)
|
||||||
|
fmt.Println(o)
|
||||||
|
waitGroup.Done()
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
waitGroup.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSync2(t *testing.T) {
|
||||||
|
var cache sync.Map
|
||||||
|
|
||||||
|
cache.Store("test", nil)
|
||||||
|
|
||||||
|
if order, ok := cache.Load("test"); ok && order != nil {
|
||||||
|
fmt.Println(order)
|
||||||
|
} else {
|
||||||
|
fmt.Println("not exist")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSync3(t *testing.T) {
|
||||||
|
var cache sync.Map
|
||||||
|
orders := make([]Order, 2)
|
||||||
|
|
||||||
|
cache.Store("test2", orders[0])
|
||||||
|
cache.Store("test", orders[0])
|
||||||
|
|
||||||
|
order, ok := cache.Load("test")
|
||||||
|
fmt.Println(ok, order)
|
||||||
|
|
||||||
|
}
|
4089
playground/xml/2018Q1.xml
Executable file
4089
playground/xml/2018Q1.xml
Executable file
File diff suppressed because it is too large
Load Diff
63
playground/xml/xml_test.go
Normal file
63
playground/xml/xml_test.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package xml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
xj "github.com/basgys/goxml2json"
|
||||||
|
"github.com/buger/jsonparser"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Person struct {
|
||||||
|
Name string `xml:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParse(t *testing.T) {
|
||||||
|
xmlFile, err := os.Open("2018Q1.xml")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer xmlFile.Close()
|
||||||
|
json, err := xj.Convert(xmlFile)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(json.String())
|
||||||
|
|
||||||
|
//err = jsonparser.ObjectEach(json.Bytes(), objectEach,"xbrl")
|
||||||
|
//if err != nil {
|
||||||
|
// fmt.Println(err)
|
||||||
|
// return
|
||||||
|
//}
|
||||||
|
|
||||||
|
// 營業收入
|
||||||
|
var revenue string
|
||||||
|
_, err = jsonparser.ArrayEach(json.Bytes(), func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
|
||||||
|
revenue, err = jsonparser.GetString(value, "#content")
|
||||||
|
fmt.Println(revenue)
|
||||||
|
}, "xbrl", "Revenue")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parse(b []byte) {
|
||||||
|
err := jsonparser.ObjectEach(b, objectEach, "xbrl")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func objectEach(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error {
|
||||||
|
fmt.Printf("[Key]: [%s]\n Value: '%s'\n Type: %s\n", string(key), string(value), dataType)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func arrayEach(value []byte, dataType jsonparser.ValueType, offset int, err error) {
|
||||||
|
fmt.Printf("Array Value: '%s'\n Type: %s\n", string(value), dataType)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user