Skip to content

Commit 3d30842

Browse files
authored
Merge pull request #77 from OpenLMIS/OLMIS-8118-java-integer-max-validation
OLMIS-8118: Validate max value on integer inputs
2 parents eb8a325 + 1f8d4c7 commit 3d30842

3 files changed

Lines changed: 138 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
==================
66

77
Improvements:
8+
* [OLMIS-8118](https://openlmis.atlassian.net/browse/OLMIS-8118): Validate max value on positive integer inputs.
89
* [SELV3-748](https://openlmis.atlassian.net/browse/SELV3-748) Resolved cookie issue causing untranslated warning messages
910
* [OLMIS-8192](https://openlmis.atlassian.net/browse/OLMIS-8192): Editable text inputs inside table cells now grow with their content.
1011

src/openlmis-form/positive-integer.directive.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,26 @@
2323
* @name openlmis-form.directive:positiveInteger
2424
*
2525
* @description
26-
* Restricts the ngModel to only allow positive integers.
26+
* Restricts the ngModel to only allow positive integers. Values larger than the maximum safe
27+
* integer in JavaScript are rejected (the 'max' validity is set to false), because parseInt
28+
* would otherwise silently overflow and send a wrong value. When the java-integer attribute is
29+
* present the limit is lowered to the maximum Java Integer value.
2730
*
2831
* @example
2932
* Extend the input element to force it to only accept positive integers as values.
3033
* ```
3134
* <input ng-model="someModel" positive-integer>
3235
* ```
36+
* Add the java-integer attribute to additionally reject values exceeding the Java Integer range.
37+
* ```
38+
* <input ng-model="someModel" positive-integer java-integer>
39+
* ```
3340
*/
41+
var JAVA_INTEGER_MAX = Math.pow(2, 31) - 1;
42+
3443
angular
3544
.module('openlmis-form')
45+
.constant('JAVA_INTEGER_MAX', JAVA_INTEGER_MAX)
3646
.directive('positiveInteger', positiveInteger);
3747

3848
function positiveInteger() {
@@ -59,7 +69,14 @@
5969
modelCtrl.$render();
6070
}
6171

62-
return transformedInput ? parseInt(transformedInput) : null;
72+
var parsed = transformedInput ? parseInt(transformedInput) : null;
73+
74+
var maxValue = attrs.hasOwnProperty('javaInteger')
75+
? JAVA_INTEGER_MAX
76+
: Number.MAX_SAFE_INTEGER;
77+
modelCtrl.$setValidity('max', !parsed || parsed <= maxValue);
78+
79+
return parsed;
6380
});
6481
}
6582
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
* This program is part of the OpenLMIS logistics management information system platform software.
3+
* Copyright © 2017 VillageReach
4+
*
5+
* This program is free software: you can redistribute it and/or modify it under the terms
6+
* of the GNU Affero General Public License as published by the Free Software Foundation, either
7+
* version 3 of the License, or (at your option) any later version.
8+
*  
9+
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
10+
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
11+
* See the GNU Affero General Public License for more details. You should have received a copy of
12+
* the GNU Affero General Public License along with this program. If not, see
13+
* http://www.gnu.org/licenses.  For additional information contact info@OpenLMIS.org. 
14+
*/
15+
describe('openlmisPositiveInteger', function() {
16+
17+
beforeEach(function() {
18+
module('openlmis-form');
19+
20+
inject(function($injector) {
21+
this.$compile = $injector.get('$compile');
22+
this.$rootScope = $injector.get('$rootScope');
23+
});
24+
25+
this.$scope = this.$rootScope.$new();
26+
27+
this.compileElement = function(extraAttrs) {
28+
this.element = this.$compile(
29+
'<form name="form_test">' +
30+
'<input name="input_test" positive-integer ' + (extraAttrs || '') +
31+
' ng-model="example"/></form>'
32+
)(this.$scope);
33+
angular.element('body').append(this.element);
34+
this.$rootScope.$apply();
35+
};
36+
37+
this.compileElement();
38+
});
39+
40+
it('should add number class', function() {
41+
expect(this.$scope.form_test.input_test.$$element.hasClass('number')).toBe(true);
42+
});
43+
44+
it('should strip non-numeric characters', function() {
45+
this.$scope.form_test.input_test.$setViewValue('12abc3');
46+
this.$scope.$digest();
47+
48+
expect(this.$scope.example).toEqual(123);
49+
});
50+
51+
it('should parse value as integer', function() {
52+
this.$scope.form_test.input_test.$setViewValue('42');
53+
this.$scope.$digest();
54+
55+
expect(this.$scope.example).toEqual(42);
56+
});
57+
58+
it('should return null for empty input', function() {
59+
this.$scope.form_test.input_test.$setViewValue('');
60+
this.$scope.$digest();
61+
62+
expect(this.$scope.example).toBeNull();
63+
});
64+
65+
describe('without java-integer attribute', function() {
66+
67+
it('should be valid for value within the safe integer range', function() {
68+
this.$scope.form_test.input_test.$setViewValue('9999999999');
69+
this.$scope.$digest();
70+
71+
expect(this.$scope.form_test.input_test.$error.max).toBeFalsy();
72+
});
73+
74+
it('should be invalid for value exceeding the max safe integer', function() {
75+
this.$scope.form_test.input_test.$setViewValue('99999999999999999');
76+
this.$scope.$digest();
77+
78+
expect(this.$scope.form_test.input_test.$error.max).toBe(true);
79+
});
80+
});
81+
82+
describe('with java-integer attribute', function() {
83+
84+
beforeEach(function() {
85+
this.compileElement('java-integer');
86+
});
87+
88+
it('should be valid for value within Java Integer range', function() {
89+
this.$scope.form_test.input_test.$setViewValue('2147483647');
90+
this.$scope.$digest();
91+
92+
expect(this.$scope.form_test.input_test.$error.max).toBeFalsy();
93+
expect(this.$scope.form_test.input_test.$valid).toBe(true);
94+
});
95+
96+
it('should be invalid for value exceeding Java Integer max', function() {
97+
this.$scope.form_test.input_test.$setViewValue('2147483648');
98+
this.$scope.$digest();
99+
100+
expect(this.$scope.form_test.input_test.$error.max).toBe(true);
101+
expect(this.$scope.example).toBe(2147483648);
102+
});
103+
104+
it('should be valid for empty value', function() {
105+
this.$scope.form_test.input_test.$setViewValue('');
106+
this.$scope.$digest();
107+
108+
expect(this.$scope.form_test.input_test.$error.max).toBeFalsy();
109+
});
110+
111+
it('should be valid for typical small quantity', function() {
112+
this.$scope.form_test.input_test.$setViewValue('100');
113+
this.$scope.$digest();
114+
115+
expect(this.$scope.form_test.input_test.$error.max).toBeFalsy();
116+
});
117+
});
118+
});

0 commit comments

Comments
 (0)