1/* 2 * Copyright (C) 2024 The Android Open Source Project 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 17import {assertDefined} from 'common/assert_utils'; 18import { 19 TamperedMessageType, 20 TamperedProtoField, 21} from 'parsers/tampered_message_type'; 22import root from 'protos/test/fake_proto/json'; 23import {PropertyTreeBuilder} from 'test/unit/property_tree_builder'; 24import { 25 PropertySource, 26 PropertyTreeNode, 27} from 'trace/tree_node/property_tree_node'; 28import {AddDefaults} from './add_defaults'; 29 30describe('AddDefaults', () => { 31 let propertyRoot: PropertyTreeNode; 32 let operation: AddDefaults; 33 let rootField: TamperedProtoField; 34 35 beforeEach(() => { 36 rootField = TamperedMessageType.tamper(root.lookupType('RootMessage')) 37 .fields['entry']; 38 propertyRoot = new PropertyTreeBuilder() 39 .setIsRoot(true) 40 .setRootId('test') 41 .setName('node') 42 .build(); 43 }); 44 45 it('adds only defaults from allowlist', () => { 46 operation = new AddDefaults(rootField, ['number_32bit']); 47 operation.apply(propertyRoot); 48 expect(propertyRoot.getAllChildren().length).toEqual(1); 49 const defaultNode = assertDefined( 50 propertyRoot.getChildByName('number_32bit'), 51 ); 52 expect(defaultNode.getValue()).toEqual(0); 53 checkAllNodesAreDefault(propertyRoot); 54 }); 55 56 it('adds all defaults from prototype definition in absence of allowlist', () => { 57 operation = new AddDefaults(rootField); 58 operation.apply(propertyRoot); 59 expect(propertyRoot.getAllChildren().length).toEqual(11); 60 checkAllNodesAreDefault(propertyRoot); 61 expect( 62 assertDefined(propertyRoot.getChildByName('array')).getValue(), 63 ).toEqual([]); 64 expect( 65 assertDefined(propertyRoot.getChildByName('number_32bit')).getValue(), 66 ).toEqual(0); 67 expect( 68 assertDefined(propertyRoot.getChildByName('number_64bit')).getValue(), 69 ).toEqual(0n); 70 expect( 71 assertDefined(propertyRoot.getChildByName('boolValue')).getValue(), 72 ).toBeFalse(); 73 }); 74 75 it('does not add defaults in denylist', () => { 76 operation = new AddDefaults(rootField, undefined, [ 77 'number_32bit', 78 'number_64bit', 79 ]); 80 operation.apply(propertyRoot); 81 82 expect(propertyRoot.getAllChildren().length).toEqual(9); 83 checkAllNodesAreDefault(propertyRoot); 84 expect(propertyRoot.getChildByName('number_32bit')).toBeUndefined(); 85 expect(propertyRoot.getChildByName('number_64bit')).toBeUndefined(); 86 }); 87 88 it('replaces undefined proto node with default node', () => { 89 operation = new AddDefaults(rootField, ['number_32bit']); 90 propertyRoot = new PropertyTreeBuilder() 91 .setIsRoot(true) 92 .setRootId('test') 93 .setName('node') 94 .setChildren([{name: 'number_32bit', value: undefined}]) 95 .build(); 96 operation.apply(propertyRoot); 97 98 expect(propertyRoot.getAllChildren().length).toEqual(1); 99 const defaultNode = assertDefined( 100 propertyRoot.getChildByName('number_32bit'), 101 ); 102 expect(defaultNode.getValue()).toEqual(0); 103 checkAllNodesAreDefault(propertyRoot); 104 }); 105 106 function checkAllNodesAreDefault(root: PropertyTreeNode) { 107 root.getAllChildren().forEach((child) => { 108 expect(child.source).toEqual(PropertySource.DEFAULT); 109 }); 110 } 111}); 112