Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion src/renderers/native/ReactNativePropRegistry.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,24 @@ class ReactNativePropRegistry {

var object = objects[id];
if (!object) {
console.warn('Invalid style with id `' + id + '`. Skipping ...');
if (id > 1 && id <= uniqueID) {
// We cannot directly test for unregistered objects because keeping a permanent registry of them
// would leak memory, however we do know that ids above 1 and below uniqueID were once registered
console.warn(
'Style with id `' + id + '` has been unregistered. Skipping ...',
);
} else {
console.warn('Invalid style with id `' + id + '`. Skipping ...');
}
return emptyObject;
}
return object;
}

static unregister(id: number): void {
// delete is used instead of setting to null so we don't slowly leak memory by keeping keys
delete objects[id];
}
}

module.exports = ReactNativePropRegistry;
80 changes: 80 additions & 0 deletions src/renderers/native/__tests__/ReactNativePropRegistry-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
'use strict';

var ReactNativePropRegistry = require('ReactNativePropRegistry');

var register = ReactNativePropRegistry.register;
var getByID = ReactNativePropRegistry.getByID;
var unregister = ReactNativePropRegistry.unregister;
var devOnlyIt = __DEV__ ? it : it.skip;

describe('ReactNativePropRegistry', () => {
describe('register', () => {
it('should return an integer', () => {
expect(typeof register({})).toBe('number');
});

it('should not return the same integer across different calls', () => {
var a = register({});
var b = register({});

expect(b).not.toBe(a);
});

devOnlyIt('should freeze the input object in __DEV__ mode', () => {
var object = {a: 1};
register(object);
expect(() => {
object.a = 2;
}).toThrowErrorMatchingSnapshot();
});
});

describe('getByID', () => {
it('should return an empty object when passed undefined, null, false, or 0', () => {
expect(getByID(undefined)).toEqual({});
expect(getByID(null)).toEqual({});
expect(getByID(false)).toEqual({});
expect(getByID(0)).toEqual({});
});

it('should warn and return an empty object when passed an unknown id', () => {
var spy = spyOn(console, 'warn');
expect(getByID(999999999999999)).toEqual({});
expect(spy).toHaveBeenCalledWith('Invalid style with id `999999999999999`. Skipping ...');
});

it('should warn and return an empty object when passed an id for an unregistered object', () => {
var spy = spyOn(console, 'warn');
var object = {a: 1};
var id = register(object);
unregister(id);
expect(getByID(id)).toEqual({});
expect(spy).toHaveBeenCalledWith('Style with id `' + id + '` has been unregistered. Skipping ...');
});

it('should return an object registered with register', () => {
var object = {a: 1};
var id = register(object);
expect(getByID(id)).toBe(object);
});
});

describe('unregister', () => {
it('should unregister objects so getByID does not return them', () => {
spyOn(console, 'warn');
var object = {a: 1};
var id = register(object);
unregister(id);
var result = getByID(id);
expect(result).not.toBe(object);
expect(result).toEqual({});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ReactNativePropRegistry register should freeze the input object in __DEV__ mode 1`] = `"Cannot assign to read only property 'a' of object '#<Object>'"`;