Skip to content

Commit 26dd547

Browse files
author
Steven Edouard
committed
Merge pull request CatalystCode#15 from CatalystCode/refactor_mocks
Refactor mocks
2 parents 27d5848 + 6921cd6 commit 26dd547

14 files changed

+325
-21
lines changed

appveyor.yml

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Test against this version of Node.js
2+
environment:
3+
nodejs_version: "4.1.2"
4+
5+
# Install scripts. (runs after repo cloning)
6+
install:
7+
# Get the latest stable version of Node.js or io.js
8+
- ps: Install-Product node $env:nodejs_version
9+
# install modules
10+
- npm install
11+
- npm install grunt-cli -g
12+
- npm install mocha -g
13+
14+
# Post-install test scripts.
15+
test_script:
16+
# Output useful info for debugging.
17+
- node --version
18+
- npm --version
19+
# run tests
20+
- npm test
21+
22+
# Don't actually build.
23+
build: off

lib/native/adv_api.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ var advApi = ffi.Library('Advapi32', {
2020
_Reserved_ LPDWORD lpReserved,
2121
_Out_opt_ LPDWORD lpType,
2222
_Out_opt_ LPBYTE lpData,
23-
_Inout_opt_ LPDWORD lpcbData
23+
_Inout_opt_ LPDWORD lpcbDataRegOpenKeyExA
2424
);
2525
*/
2626
RegQueryValueExA: ['uint64', [types.HKEY, 'string', 'pointer', types.LPDWORD, types.LPBYTE, types.LPDWORD]],

lib/registry.js

+7-8
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ var api = {
1515
throw 'The key ' + preDefinedKey + ' is not valid. Use the windef module for the list of predefined keys';
1616
}
1717

18-
var pHkey = ref.alloc(types.PHKEY);
18+
var pHkey = ref.alloc(types.PHKEY, new Buffer(ref.sizeof.pointer));
19+
console.log('PHKEY LENGTH: ' + pHkey.deref().length);
1920
var result = advApi.RegOpenKeyExA(preDefinedKey, subKeyName, 0, accessLevel, pHkey);
2021
debug('result:' + result);
2122
if (result !== 0) {
@@ -25,7 +26,7 @@ var api = {
2526
return new Key(pHkey, subKeyName);
2627
},
2728
openKeyFromKeyObject: function (keyObject, subKeyName, accessLevel) {
28-
var pHkey = ref.alloc(types.PHKEY);
29+
var pHkey = ref.alloc(types.PHKEY, new Buffer(ref.sizeof.pointer));
2930

3031
// RegOpenKeyEx can also take an HKEY in addition to a predefined value
3132
var advApi2 = ffi.Library('Advapi32', {
@@ -40,11 +41,10 @@ var api = {
4041
return new Key(pHkey, subKeyName);
4142
},
4243
queryValueForKeyObject: function (key, valueName) {
43-
var pKeyDataLength = ref.alloc(types.LPDWORD),
44-
pKeyType = ref.alloc(types.LPDWORD);
44+
var pKeyDataLength = ref.alloc(types.LPDWORD, new Buffer(ref.sizeof.pointer)),
45+
pKeyType = ref.alloc(types.LPDWORD, new Buffer(ref.sizeof.pointer));
4546
// QUERY FOR VALUE SIZE & TYPE
4647
var result = advApi.RegQueryValueExA(key.handle.deref(), valueName, null, pKeyType, null, pKeyDataLength);
47-
4848
// READ VALUE
4949
var value = new Buffer(pKeyDataLength.readUInt32LE()),
5050
valueType = pKeyType.readUInt32LE();
@@ -121,9 +121,9 @@ var api = {
121121
}
122122
},
123123
createKey: function (key, subKeyName, accessLevel) {
124-
var pHkey = ref.alloc(types.PHKEY);
124+
var pHkey = ref.alloc(types.PHKEY, new Buffer(ref.sizeof.pointer));
125125

126-
var result = advApi.RegCreateKeyExA(key.handle.deref(), subKeyName, null, null, 0 /*REG_OPTION_NON_VOLATILE*/ , accessLevel, null, pHkey, null);
126+
var result = advApi.RegCreateKeyExA(key.handle.deref(), subKeyName, null, null, windef.REG_OPTION_NON_VOLATILE, accessLevel, null, pHkey, null);
127127

128128
if (result !== 0) {
129129
throw 'Failed to open key error: ' + error[result];
@@ -137,7 +137,6 @@ var api = {
137137
}
138138
},
139139
closeKey: function (key) {
140-
debug('KEY:' + key);
141140
var result = advApi.RegCloseKey(key.handle.deref());
142141

143142
if (result !== 0) {

lib/types.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ var types = {
77
HWND: ref.refType(ref.types.void),
88
BYTE: ref.types.uint8,
99
HKEY: ref.refType(ref.types.void),
10-
PVOID: ref.refType(ref.types.void),
10+
PVOID: ref.refType('pointer'),
1111
HANDLE: ref.refType(ref.types.void),
1212
HINSTANCE: ref.refType(ref.types.void),
1313
LPCTSTR: ref.refType(ref.types.CString),

lib/utils.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ var ref = require('ref'),
44
shell32 = require('./native/shell32'),
55
windef = require('./windef'),
66
debug = require('debug')('windows-registry'),
7-
registry = require('./registry');
7+
registry = require('./registry'),
8+
debug = require('debug')('windows-registry');
89

910
// pass in default values for members
1011
var lpVerb = 'runas';

lib/windef.js

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ module.exports = {
4444
REG_MULTI_SZ: 7,
4545
REG_RESOURCE_LIST: 8
4646
},
47+
REG_OPTION_NON_VOLATILE: 0,
4748
/*
4849
typedef struct _SHELLEXECUTEINFO {
4950
DWORD cbSize;

package.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@
1818
},
1919
"devDependencies": {
2020
"grunt": "^0.4.5",
21-
"grunt-mocha-cli": "^2.0.0",
22-
"load-grunt-tasks": "^3.3.0",
2321
"grunt-contrib-jshint": "^0.11.3",
2422
"grunt-contrib-watch": "^0.6.1",
2523
"grunt-jsbeautifier": "^0.2.10",
26-
"grunt-jscs": "^2.1.0"
24+
"grunt-jscs": "^2.1.0",
25+
"grunt-mocha-cli": "^2.0.0",
26+
"load-grunt-tasks": "^3.3.0",
27+
"mockery": "^1.4.0"
2728
},
2829
"scripts": {
2930
"test": "grunt test"

test/file_association.js

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
/* global describe, it */
22
'use strict';
3+
if (process.env.TEST_MOCKS_ON) {
4+
require('./test_helper');
5+
}
6+
37
var utils = require('../lib/utils'),
48
assert = require('assert');
59

test/key.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
/* global describe, it */
22
'use strict';
3-
var windef = require('../lib/windef'),
4-
Key = require('../lib/key'),
5-
assert = require('assert');
3+
require('./test_helper');
4+
var assert = require('assert'),
5+
windef = require('../lib/windef'),
6+
Key = require('../lib/key');
67

78
describe('Key Open Tests', () => {
89
it('Should create a key given a subkey', () => {
@@ -65,6 +66,7 @@ describe('Set / Query Value Tests', function () {
6566
key.setValue('test_value_name', windef.REG_VALUE_TYPE.REG_SZ, 'test_value');
6667

6768
var value = key.getValue('test_value_name');
69+
6870
assert.equal(value, 'test_value');
6971
key.close();
7072
});

test/mock/adv_api.js

+220
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
/* globals Buffer */
2+
/**
3+
* A very dumb minimal implementation of the Windows Registry.
4+
* Enough to run our tests
5+
*/
6+
'use strict';
7+
var assert = require('assert'),
8+
windef = require('../../lib/windef'),
9+
types = require('../../lib/types'),
10+
debug = require('debug')('windows-registry'),
11+
ref = require('ref');
12+
13+
/*
14+
* Dumb O(n) search for value inside object
15+
*/
16+
function findValueInHash(value, hash) {
17+
var found = false;
18+
for (let k in hash) {
19+
if (hash[k] === value) {
20+
found = true;
21+
break;
22+
}
23+
}
24+
return found;
25+
}
26+
27+
var keys = {
28+
};
29+
keys[windef.HKEY.HKEY_CLASSES_ROOT] = {
30+
predefValue: true,
31+
open: false,
32+
values: {
33+
}
34+
};
35+
var mockIndex = 0x00000001;
36+
37+
var advApi = {
38+
/*
39+
LONG WINAPI RegQueryValueEx(
40+
_In_ HKEY hKey,
41+
_In_opt_ LPCTSTR lpValueName,
42+
_Reserved_ LPDWORD lpReserved,
43+
_Out_opt_ LPDWORD lpType,
44+
_Out_opt_ LPBYTE lpData,
45+
_Inout_opt_ LPDWORD lpcbData
46+
);
47+
*/
48+
RegQueryValueExA: function (hKey, valueName, shouldBeNull, lpType, lpData, lpcbData) {
49+
debug('RegQueryValueExA');
50+
if (lpData === null) {
51+
debug(keys[hKey.address()].values.test_value_name);
52+
lpType.writeUInt32LE(windef.REG_VALUE_TYPE.REG_SZ, 0);
53+
lpcbData.writeUInt32LE(keys[hKey.address()].values[valueName].length, 0);
54+
return 0;
55+
}
56+
57+
lpData.write(keys[hKey.address()].values[valueName].value, 'utf8');
58+
lpType.writeUInt16LE(windef.REG_VALUE_TYPE.REG_SZ);
59+
return 0;
60+
},
61+
/*
62+
LONG WINAPI RegOpenKeyEx(
63+
_In_ HKEY hKey,
64+
_In_opt_ LPCTSTR lpSubKey,
65+
_In_ DWORD ulOptions,
66+
_In_ REGSAM samDesired,
67+
_Out_ PHKEY phkResult
68+
);
69+
*/
70+
RegOpenKeyExA: function (hKey, subKeyName, shouldBeZero, accessLevel, pHkey) {
71+
var accessLevelFound = findValueInHash(accessLevel, windef.KEY_ACCESS);
72+
debug('Mock: RegOpenKeyExA subkey: ' + subKeyName);
73+
if (hKey.address) {
74+
debug('Mock: hKey address:' + hKey.address());
75+
}
76+
debug('keys:');
77+
debug(keys);
78+
// predefined key
79+
ref.writeUInt64LE(pHkey.deref(), 0, mockIndex);
80+
mockIndex += 1;
81+
if (typeof hKey === 'number') {
82+
assert(findValueInHash(hKey, windef.HKEY), 'Mock: Invalid predefined key specified');
83+
84+
if (!keys[hKey]) {
85+
debug('failed to find key for ' + hKey + ' current keys:');
86+
debug(keys);
87+
// FILE NOT FOUND
88+
return 2;
89+
}
90+
keys[pHkey.deref().address()] = {
91+
opened: true,
92+
values: {
93+
94+
}
95+
};
96+
} else {
97+
assert(hKey.constructor === Buffer);
98+
99+
if (!keys[hKey.address()]) {
100+
debug('failed to find key for ' + hKey.address() + ' current keys:');
101+
debug(keys);
102+
// FILE NOT FOUND
103+
return 2;
104+
}
105+
keys[hKey.address()].open = true;
106+
keys[pHkey.deref().address()] = keys[hKey.address()];
107+
}
108+
109+
assert(typeof subKeyName === 'string');
110+
assert(shouldBeZero === 0);
111+
assert(accessLevelFound, 'Mock: Invalid access level specified');
112+
assert(pHkey.deref().constructor === Buffer);
113+
114+
return 0;
115+
},
116+
/*
117+
LONG WINAPI RegSetValueEx(
118+
_In_ HKEY hKey,
119+
_In_opt_ LPCTSTR lpValueName,
120+
_Reserved_ DWORD Reserved,
121+
_In_ DWORD dwType,
122+
_In_ const BYTE *lpData,
123+
_In_ DWORD cbData
124+
);
125+
*/
126+
RegSetValueExA: function (hKey, valueName, shouldBeNull, valueType, valueBuffer, bufferLength) {
127+
debug('Mock: RegSetValueExA');
128+
// predefined key
129+
if (typeof hKey === 'number') {
130+
assert(findValueInHash(hKey, windef.HKEY), 'Mock: Invalid predefined key specified');
131+
} else {
132+
assert(hKey.constructor === Buffer);
133+
}
134+
assert(typeof valueName === 'string');
135+
assert(typeof valueType === 'number');
136+
assert(valueBuffer.constructor === Buffer);
137+
assert(typeof bufferLength === 'number');
138+
139+
keys[hKey.address()].values[valueName] = {
140+
valueType: valueType,
141+
value: ref.readCString(valueBuffer),
142+
length: bufferLength
143+
};
144+
return 0;
145+
},
146+
/**
147+
* LONG WINAPI RegCreateKeyEx(
148+
_In_ HKEY hKey,
149+
_In_ LPCTSTR lpSubKey,
150+
_Reserved_ DWORD Reserved,
151+
_In_opt_ LPTSTR lpClass,
152+
_In_ DWORD dwOptions,
153+
_In_ REGSAM samDesired,
154+
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
155+
_Out_ PHKEY phkResult,
156+
_Out_opt_ LPDWORD lpdwDisposition
157+
);
158+
*/
159+
RegCreateKeyExA: function (hKey, subKeyName, shouldBeNull, shouldBeNull2, securityAttributes, accessLevel, shouldBeNull3, pHkey, shouldBeNull4) {
160+
debug('Mock: RegCreateKeyExA');
161+
assert(hKey.constructor === Buffer);
162+
assert(typeof subKeyName === 'string');
163+
assert(shouldBeNull === null);
164+
assert(shouldBeNull2 === null);
165+
assert(shouldBeNull3 === null);
166+
assert(shouldBeNull4 === null);
167+
assert.equal(securityAttributes, 0, 'Mock: Security Attributes are not supported yet');
168+
assert(findValueInHash(accessLevel, windef.KEY_ACCESS), 'Mock: Invalid access level specified');
169+
assert(pHkey.deref().constructor === Buffer);
170+
debug('Mock: Writing: ' + mockIndex + ' 64 bit dummy pointer to buffer with length: ' + pHkey.deref().length);
171+
172+
ref.writeUInt64LE(pHkey.deref(), 0, mockIndex);
173+
debug('Mock: Wrote 64 bit dummy pointer');
174+
mockIndex += 1;
175+
debug('Mock: Creating fake key for: ' + hKey.address());
176+
debug('Subkey: ' + subKeyName);
177+
keys[hKey.address()] = {
178+
opened: true,
179+
subkeys: {
180+
subKeyName: ''
181+
},
182+
values: {
183+
184+
}
185+
};
186+
187+
return 0;
188+
},
189+
/*
190+
LONG WINAPI RegDeleteTree(
191+
_In_ HKEY hKey,
192+
_In_opt_ LPCTSTR lpSubKey
193+
);
194+
*/
195+
RegDeleteTreeA: function (hKey, subKeyName) {
196+
if (typeof hKey === 'number') {
197+
assert(findValueInHash(hKey, windef.HKEY), 'Mock: Invalid predefined key specified');
198+
} else {
199+
assert(hKey.constructor === Buffer, 'Mock: hKey should be of type buffer if not a number');
200+
}
201+
202+
assert(typeof subKeyName === 'string' || subKeyName === undefined);
203+
delete keys[hKey.address()];
204+
return 0;
205+
},
206+
/*
207+
LONG WINAPI RegCloseKey(
208+
_In_ HKEY hKey
209+
);
210+
*/
211+
RegCloseKey: function (hKey) {
212+
debug('Mock: RegCloseKey');
213+
assert.equal(hKey.indirections, types.HKEY.indirections);
214+
215+
delete keys[hKey.address()];
216+
return 0;
217+
}
218+
};
219+
220+
module.exports = advApi;

0 commit comments

Comments
 (0)