Skip to content

Commit 9f8b4d4

Browse files
Add node version model (#766)
* add NodeVersion model * add NodeVersion test * lint * fix text titles * fix typo * fix jsdoc
1 parent 3341245 commit 9f8b4d4

File tree

4 files changed

+284
-1
lines changed

4 files changed

+284
-1
lines changed

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/model/node/NodeVersion.ts

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Copyright 2021 NEM
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
export class NodeVersion {
18+
/**
19+
* Create a NodeVersion from a given raw version number.
20+
* @param {number} rawNodeVersion - Node version in number format.
21+
* ex: 655367
22+
* @returns {NodeVersion}
23+
*/
24+
public static createFromRawNodeVersion(rawNodeVersion: number): NodeVersion {
25+
if (!NodeVersion.isValidRawNodeVersion(rawNodeVersion)) {
26+
throw new Error(`Invalid node version number '${rawNodeVersion}'`);
27+
}
28+
29+
return new NodeVersion(rawNodeVersion);
30+
}
31+
32+
/**
33+
* Create a NodeVersion from a given formatted version string.
34+
* @param {string} formattedNodeVersion - Node version in string format.
35+
* ex: 0.10.0.7
36+
* @returns {NodeVersion}
37+
*/
38+
public static createFromFormattedNodeVersion(formattedNodeVersion: string): NodeVersion {
39+
if (!NodeVersion.isValidFormattedNodeVersion(formattedNodeVersion)) {
40+
throw new Error(`Invalid node version string '${formattedNodeVersion}'`);
41+
}
42+
43+
const placeholderHex = '00';
44+
const hexVersionNumber = formattedNodeVersion
45+
.split('.')
46+
.map((value) => (placeholderHex + parseInt(value).toString(16)).slice(-2))
47+
.join('');
48+
49+
const rawVersionNumber = parseInt(hexVersionNumber, 16);
50+
return new NodeVersion(rawVersionNumber);
51+
}
52+
53+
/**
54+
* Determines the validity of a raw node version number.
55+
* @param {string} rawNodeVersion The raw node version number. Expected format 655367
56+
* @returns {boolean} true if the raw node version number is valid, false otherwise.
57+
*/
58+
public static isValidRawNodeVersion = (rawNodeVersion: number): boolean => {
59+
const maxRawNodeVersion = 4294967295;
60+
const minRawNodeVersion = 0;
61+
62+
return Number.isInteger(rawNodeVersion) && rawNodeVersion >= minRawNodeVersion && rawNodeVersion <= maxRawNodeVersion;
63+
};
64+
65+
/**
66+
* Determines the validity of a formatted node version string.
67+
* @param {string} formattedNodeVersion The formatted node version string. Expected format: 0.10.0.7
68+
* @returns {boolean} true if the formatted node version string is valid, false otherwise.
69+
*/
70+
public static isValidFormattedNodeVersion = (formattedNodeVersion: string): boolean => {
71+
const maxFormattedNodeVersionChunkValue = 255;
72+
const minFormattedNodeVersionChunkValue = 0;
73+
74+
const versionChuncks = formattedNodeVersion.split('.').map((value) => parseInt(value));
75+
76+
if (versionChuncks.length !== 4) {
77+
return false;
78+
}
79+
80+
const isVersionChuncksValid = !versionChuncks.find(
81+
(value) => isNaN(value) || value < minFormattedNodeVersionChunkValue || value > maxFormattedNodeVersionChunkValue,
82+
);
83+
84+
return isVersionChuncksValid;
85+
};
86+
87+
/**
88+
* @internal
89+
* @param nodeVersion
90+
*/
91+
private constructor(
92+
/**
93+
* The raw node version value.
94+
*/
95+
private readonly nodeVersion: number,
96+
) {}
97+
98+
/**
99+
* Get node version in formatted format ex: 0.10.0.7
100+
* @returns {string}
101+
*/
102+
public formatted(): string {
103+
const placeholderHex = '00000000';
104+
const hexNodeVersion = (placeholderHex + this.nodeVersion.toString(16)).slice(-8);
105+
const formattedNodeVersion = hexNodeVersion
106+
.match(/.{1,2}/g)!
107+
.map((hex) => parseInt(hex, 16))
108+
.join('.');
109+
110+
return formattedNodeVersion;
111+
}
112+
113+
/**
114+
* Get node version in the raw numeric format ex: 655367.
115+
* @returns {number}
116+
*/
117+
public raw(): number {
118+
return this.nodeVersion;
119+
}
120+
121+
/**
122+
* Compares node versions for equality
123+
* @param nodeVersion - Node version to compare
124+
* @returns {boolean}
125+
*/
126+
public equals(nodeVersion: any): boolean {
127+
if (nodeVersion instanceof NodeVersion) {
128+
return this.nodeVersion === nodeVersion.raw();
129+
}
130+
131+
return false;
132+
}
133+
}

src/model/node/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
export * from './NodeHealth';
44
export * from './NodeInfo';
55
export * from './NodeTime';
6+
export * from './NodeVersion';
67
export * from './RoleType';
78
export * from './ServerInfo';
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* Copyright 2021 NEM
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { expect } from 'chai';
18+
import { NodeVersion } from '../../../src/model/node/NodeVersion';
19+
20+
describe('NodeVersion', () => {
21+
const validRawVersion1 = 4294967295;
22+
const validFormattedVersion1 = '255.255.255.255';
23+
const validRawVersion2 = 0;
24+
const validFormattedVersion2 = '0.0.0.0';
25+
const validRawVersion3 = 655367;
26+
const validFormattedVersion3 = '0.10.0.7';
27+
28+
const invalidFormattedVersion1 = '0.0.0.0.0';
29+
const invalidFormattedVersion2 = '-1.0.0.0';
30+
const invalidFormattedVersion3 = '0.0.0.256';
31+
const invalidFormattedVersion4 = 'some text';
32+
const invalidFormattedVersion5 = '';
33+
34+
const invalidRawVersion1 = -1231;
35+
const invalidRawVersion2 = 42949672955;
36+
const invalidRawVersion3 = 23.34;
37+
const invalidRawVersion4 = Infinity;
38+
39+
it('createComplete a NodeVersion by given raw version', () => {
40+
const nodeVersion = NodeVersion.createFromRawNodeVersion(validRawVersion1);
41+
expect(nodeVersion.raw()).to.be.equal(validRawVersion1);
42+
});
43+
44+
it('createComplete a NodeVersion by given raw version', () => {
45+
const nodeVersion = NodeVersion.createFromRawNodeVersion(validRawVersion2);
46+
expect(nodeVersion.raw()).to.be.equal(validRawVersion2);
47+
});
48+
49+
it('createComplete a NodeVersion by given raw version', () => {
50+
const nodeVersion = NodeVersion.createFromRawNodeVersion(validRawVersion3);
51+
expect(nodeVersion.raw()).to.be.equal(validRawVersion3);
52+
});
53+
54+
it('createComplete a NodeVersion by given formatted version', () => {
55+
const nodeVersion = NodeVersion.createFromFormattedNodeVersion(validFormattedVersion1);
56+
expect(nodeVersion.raw()).to.be.equal(validRawVersion1);
57+
});
58+
59+
it('createComplete a NodeVersion by given formatted version', () => {
60+
const nodeVersion = NodeVersion.createFromFormattedNodeVersion(validFormattedVersion2);
61+
expect(nodeVersion.raw()).to.be.equal(validRawVersion2);
62+
});
63+
64+
it('createComplete a NodeVersion by given formatted version', () => {
65+
const nodeVersion = NodeVersion.createFromFormattedNodeVersion(validFormattedVersion3);
66+
expect(nodeVersion.raw()).to.be.equal(validRawVersion3);
67+
});
68+
69+
it('print formatted node version', () => {
70+
const nodeVersion = NodeVersion.createFromRawNodeVersion(validRawVersion1);
71+
expect(nodeVersion.formatted()).to.be.equal(validFormattedVersion1);
72+
});
73+
74+
it('print formatted node version', () => {
75+
const nodeVersion = NodeVersion.createFromRawNodeVersion(validRawVersion2);
76+
expect(nodeVersion.formatted()).to.be.equal(validFormattedVersion2);
77+
});
78+
79+
it('print formatted node version', () => {
80+
const nodeVersion = NodeVersion.createFromRawNodeVersion(validRawVersion3);
81+
expect(nodeVersion.formatted()).to.be.equal(validFormattedVersion3);
82+
});
83+
84+
it('should throw Error when negative raw version provided', () => {
85+
expect(() => {
86+
NodeVersion.createFromRawNodeVersion(invalidRawVersion1);
87+
}).to.throw(`Invalid node version number '${invalidRawVersion1}'`);
88+
});
89+
90+
it('should throw Error when too large raw version provided', () => {
91+
expect(() => {
92+
NodeVersion.createFromRawNodeVersion(invalidRawVersion2);
93+
}).to.throw(`Invalid node version number '${invalidRawVersion2}'`);
94+
});
95+
96+
it('should throw Error when float number raw version provided', () => {
97+
expect(() => {
98+
NodeVersion.createFromRawNodeVersion(invalidRawVersion3);
99+
}).to.throw(`Invalid node version number '${invalidRawVersion3}'`);
100+
});
101+
102+
it('should throw Error when Infinity number raw version provided', () => {
103+
expect(() => {
104+
NodeVersion.createFromRawNodeVersion(invalidRawVersion4);
105+
}).to.throw(`Invalid node version number '${invalidRawVersion4}'`);
106+
});
107+
108+
it('should throw Error when invalid formatted version provided', () => {
109+
expect(() => {
110+
NodeVersion.createFromFormattedNodeVersion(invalidFormattedVersion1);
111+
}).to.throw(`Invalid node version string '${invalidFormattedVersion1}'`);
112+
});
113+
114+
it('should throw Error when invalid formatted version with one negative provided', () => {
115+
expect(() => {
116+
NodeVersion.createFromFormattedNodeVersion(invalidFormattedVersion2);
117+
}).to.throw(`Invalid node version string '${invalidFormattedVersion2}'`);
118+
});
119+
120+
it('should throw Error when invalid formatted version with one large provided', () => {
121+
expect(() => {
122+
NodeVersion.createFromFormattedNodeVersion(invalidFormattedVersion3);
123+
}).to.throw(`Invalid node version string '${invalidFormattedVersion3}'`);
124+
});
125+
126+
it('should throw Error when invalid text string provided', () => {
127+
expect(() => {
128+
NodeVersion.createFromFormattedNodeVersion(invalidFormattedVersion4);
129+
}).to.throw(`Invalid node version string '${invalidFormattedVersion4}'`);
130+
});
131+
132+
it('should throw Error when empty string provided', () => {
133+
expect(() => {
134+
NodeVersion.createFromFormattedNodeVersion(invalidFormattedVersion5);
135+
}).to.throw(`Invalid node version string '${invalidFormattedVersion5}'`);
136+
});
137+
138+
it('should equal versions', () => {
139+
const version = NodeVersion.createFromRawNodeVersion(validRawVersion1);
140+
const compareVersion = NodeVersion.createFromRawNodeVersion(validRawVersion1);
141+
expect(version.equals(compareVersion)).to.be.equal(true);
142+
});
143+
144+
it('should not equal versions', () => {
145+
const version = NodeVersion.createFromRawNodeVersion(validRawVersion1);
146+
const compareVersion = NodeVersion.createFromRawNodeVersion(validRawVersion2);
147+
expect(version.equals(compareVersion)).to.be.equal(false);
148+
});
149+
});

0 commit comments

Comments
 (0)