Repository: gopcua/opcua (go)

Issue:
Build in 32 bit environment fails
When crosscompiling for a 32 bit environment, I get the following two issues:
```
.../src/github.com/gopcua/opcua/ua/node_id.go:133:22: constant 4294967295 overflows int
.../src/github.com/gopcua/opcua/ua/node_id.go:250:10: constant 4294967295 overflows int
```

The first issue arises since `strconv.Atoi` a few lines earlier returns an `int` which in my system is 32 bit and thus cannot be compared to an `uint32`. Using `ParseUint` instead solved the problem:
```go
id, err := strconv.ParseUint(idval[2:], 10, 32)
```

The second issue is similar, but for that I made an uglier solution to get it to work by changing the input argument of SetIntID to an `uint32` and fiddling a bit with casting etc in the code below.

This relates to commit b9119dc of `ua/node_id.go`

Pull request description:
Issue #167: 32bit build fails
Fix code for 32 and 64 bit platforms

Fixes #167

Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 6b22fd4..9468093 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -1,10 +1,14 @@
 version: 2
+
 workflows:
   version: 2
   test:
     jobs:
       - test-1.11
+      - test-1.11-32bit
       - test-1.12
+      - test-1.12-32bit
+
 jobs:
   test-1.11:
     docker:
@@ -20,7 +24,19 @@ jobs:
           key: go-mod-{{ checksum "go.sum" }}
           paths:
             - "/go/pkg/mod"
+  test-1.11-32bit:
+    docker:
+      - image: 'circleci/golang:1.11'
+    environment:
+      GOARCH=386
+    steps: *ref_0
   test-1.12:
     docker:
       - image: 'circleci/golang:1.12'
     steps: *ref_0
+  test-1.12-32bit:
+    docker:
+      - image: 'circleci/golang:1.12'
+    environment:
+      GOARCH=386
+    steps: *ref_0
diff --git a/ua/node_id.go b/ua/node_id.go
index 66fdcce..30ea0f8 100644
--- a/ua/node_id.go
+++ b/ua/node_id.go
@@ -121,7 +121,7 @@ func NewNodeID(s string) (*NodeID, error) {
 	// parse identifier
 	switch {
 	case strings.HasPrefix(idval, "i="):
-		id, err := strconv.Atoi(idval[2:])
+		id, err := strconv.ParseUint(idval[2:], 10, 64)
 		if err != nil {
 			return nil, fmt.Errorf("invalid numeric id: %s", s)
 		}
@@ -191,13 +191,13 @@ func (n *NodeID) SetIndexFlag() {
 
 // Namespace returns the namespace id. For two byte node ids
 // this will always be zero.
-func (n *NodeID) Namespace() int {
-	return int(n.ns)
+func (n *NodeID) Namespace() uint16 {
+	return n.ns
 }
 
 // SetNamespace sets the namespace id. It returns an error
 // if the id is not within the range of the node id type.
-func (n *NodeID) SetNamespace(v int) error {
+func (n *NodeID) SetNamespace(v uint16) error {
 	switch n.Type() {
 	case NodeIDTypeTwoByte:
 		if v != 0 {
@@ -206,14 +206,14 @@ func (n *NodeID) SetNamespace(v int) error {
 		return nil
 
 	case NodeIDTypeFourByte:
-		if max := math.MaxUint8; v < 0 || v > max {
+		if max := uint16(math.MaxUint8); v > max {
 			return fmt.Errorf("out of range [0..%d]: %d", max, v)
 		}
 		n.ns = uint16(v)
 		return nil
 
 	default:
-		if max := math.MaxUint16; v < 0 || v > max {
+		if max := uint16(math.MaxUint16); v > max {
 			return fmt.Errorf("out of range [0..%d]: %d", max, v)
 		}
 		n.ns = uint16(v)
@@ -224,30 +224,30 @@ func (n *NodeID) SetNamespace(v int) error {
 // IntID returns the identifier value if the type is
 // TwoByte, FourByte or Numeric. For all other types IntID
 // returns 0.
-func (n *NodeID) IntID() int {
-	return int(n.nid)
+func (n *NodeID) IntID() uint32 {
+	return n.nid
 }
 
 // SetIntID sets the identifier value for two byte, four byte and
 // numeric node ids. It returns an error for other types.
-func (n *NodeID) SetIntID(v int) error {
+func (n *NodeID) SetIntID(v uint32) error {
 	switch n.Type() {
 	case NodeIDTypeTwoByte:
-		if max := math.MaxUint8; v < 0 || v > max {
+		if max := uint32(math.MaxUint8); v > max {
 			return fmt.Errorf("out of range [0..%d]: %d", max, v)
 		}
 		n.nid = uint32(v)
 		return nil
 
 	case NodeIDTypeFourByte:
-		if max := math.MaxUint16; v < 0 || v > max {
+		if max := uint32(math.MaxUint16); v > max {
 			return fmt.Errorf("out of range [0..%d]: %d", max, v)
 		}
 		n.nid = uint32(v)
 		return nil
 
 	case NodeIDTypeNumeric:
-		if max := math.MaxUint32; v < 0 || v > max {
+		if max := uint32(math.MaxUint32); v > max {
 			return fmt.Errorf("out of range [0..%d]: %d", max, v)
 		}
 		n.nid = uint32(v)


Test patch:
diff --git a/ua/node_id_test.go b/ua/node_id_test.go
index d463cbc..513c077 100644
--- a/ua/node_id_test.go
+++ b/ua/node_id_test.go
@@ -158,7 +158,7 @@ func TestSetIntID(t *testing.T) {
 	tests := []struct {
 		name string
 		n    *NodeID
-		v    int
+		v    uint32
 		err  error
 	}{
 		// happy flows
@@ -179,42 +179,18 @@ func TestSetIntID(t *testing.T) {
 		},
 
 		// error flows
-		{
-			name: "TwoByte.tooSmall",
-			n:    NewTwoByteNodeID(1),
-			v:    -1,
-			err:  errors.New("out of range [0..255]: -1"),
-		},
 		{
 			name: "TwoByte.tooBig",
 			n:    NewTwoByteNodeID(1),
 			v:    256,
 			err:  errors.New("out of range [0..255]: 256"),
 		},
-		{
-			name: "FourByte.tooSmall",
-			n:    NewFourByteNodeID(0, 1),
-			v:    -1,
-			err:  errors.New("out of range [0..65535]: -1"),
-		},
 		{
 			name: "FourByte.tooBig",
 			n:    NewFourByteNodeID(0, 1),
 			v:    65536,
 			err:  errors.New("out of range [0..65535]: 65536"),
 		},
-		{
-			name: "Numeric.tooSmall",
-			n:    NewNumericNodeID(0, 1),
-			v:    -1,
-			err:  errors.New("out of range [0..4294967295]: -1"),
-		},
-		{
-			name: "Numeric.toobBig",
-			n:    NewNumericNodeID(0, 1),
-			v:    4294967296,
-			err:  errors.New("out of range [0..4294967295]: 4294967296"),
-		},
 		{
 			name: "String.incompatible",
 			n:    NewStringNodeID(0, "a"),
@@ -340,7 +316,7 @@ func TestSetNamespace(t *testing.T) {
 	tests := []struct {
 		name string
 		n    *NodeID
-		v    int
+		v    uint16
 		err  error
 	}{
 		// happy flows
@@ -367,66 +343,12 @@ func TestSetNamespace(t *testing.T) {
 			v:    1,
 			err:  errors.New("out of range [0..0]: 1"),
 		},
-		{
-			name: "FourByte.tooSmall",
-			n:    NewFourByteNodeID(0, 1),
-			v:    -1,
-			err:  errors.New("out of range [0..255]: -1"),
-		},
 		{
 			name: "FourByte.tooBig",
 			n:    NewFourByteNodeID(0, 1),
 			v:    256,
 			err:  errors.New("out of range [0..255]: 256"),
 		},
-		{
-			name: "Numeric.tooSmall",
-			n:    NewNumericNodeID(0, 1),
-			v:    -1,
-			err:  errors.New("out of range [0..65535]: -1"),
-		},
-		{
-			name: "Numeric.toobBig",
-			n:    NewNumericNodeID(0, 1),
-			v:    65536,
-			err:  errors.New("out of range [0..65535]: 65536"),
-		},
-		{
-			name: "String.tooSmall",
-			n:    NewStringNodeID(0, "a"),
-			v:    -1,
-			err:  errors.New("out of range [0..65535]: -1"),
-		},
-		{
-			name: "String.tooBig",
-			n:    NewStringNodeID(0, "a"),
-			v:    65536,
-			err:  errors.New("out of range [0..65535]: 65536"),
-		},
-		{
-			name: "GUID.tooSmall",
-			n:    NewGUIDNodeID(0, "a"),
-			v:    -1,
-			err:  errors.New("out of range [0..65535]: -1"),
-		},
-		{
-			name: "GUID.tooBig",
-			n:    NewGUIDNodeID(0, "a"),
-			v:    65536,
-			err:  errors.New("out of range [0..65535]: 65536"),
-		},
-		{
-			name: "Opaque.tooSmall",
-			n:    NewByteStringNodeID(0, []byte{'a'}),
-			v:    -1,
-			err:  errors.New("out of range [0..65535]: -1"),
-		},
-		{
-			name: "Opaque.tooBig",
-			n:    NewByteStringNodeID(0, []byte{'a'}),
-			v:    65536,
-			err:  errors.New("out of range [0..65535]: 65536"),
-		},
 	}
 
 	for _, tt := range tests {