Skip to content

Commit

Permalink
fix: added test for mapInputHelper #none
Browse files Browse the repository at this point in the history
Signed-off-by: James <[email protected]>
  • Loading branch information
james-union committed May 26, 2022
1 parent 972afb4 commit 7eaeb78
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,31 @@ export function nestedCollectionInputTypeDefinition(
},
};
}

export function mapInputTypeDefinition(typeDefinition: InputTypeDefinition): InputTypeDefinition {
return {
literalType: {
mapValueType: typeDefinition.literalType,
},
type: InputType.Map,
subtype: typeDefinition,
};
}

export function nestedMapInputTypeDefinition(
typeDefinition: InputTypeDefinition,
): InputTypeDefinition {
return {
literalType: {
mapValueType: {
mapValueType: typeDefinition.literalType,
},
},
type: InputType.Map,
subtype: {
literalType: { mapValueType: typeDefinition.literalType },
type: InputType.Map,
subtype: typeDefinition,
},
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ import { InputTypeDefinition, InputValue } from '../types';
import { getHelperForInput } from './getHelperForInput';
import { ConverterInput, InputHelper, InputValidatorParams } from './types';
import t from '../../../common/strings';
import { parseJSON } from './parseJson';
import { literalNone } from './constants';

function parseMap(map: string) {
const parsed = parseJSON(map);
if (typeof parsed !== 'object') {
throw new Error(t('valueNotParse'));
}
return parsed;
}

function fromLiteral(literal: Core.ILiteral, { subtype }: InputTypeDefinition): InputValue {
if (!subtype) {
Expand Down Expand Up @@ -33,13 +43,23 @@ function toLiteral({ value, typeDefinition: { subtype } }: ConverterInput): Core
if (!subtype) {
throw new Error(t('missingMapSubType'));
}
const obj = JSON.parse(value.toString());
const key = Object.keys(obj)?.[0];
let parsed: { [key: string]: any };
// If we're processing a nested map, it may already have been parsed
if (typeof value === 'object') {
parsed = value;
} else {
const stringValue = typeof value === 'string' ? value : value.toString();
if (!stringValue.length) {
return literalNone();
}
parsed = parseMap(stringValue);
}
const key = Object.keys(parsed)?.[0];

const helper = getHelperForInput(subtype.type);

return {
map: { literals: { [key]: helper.toLiteral({ value: obj[key], typeDefinition: subtype }) } },
map: { literals: { [key]: helper.toLiteral({ value: parsed[key], typeDefinition: subtype }) } },
};
}

Expand All @@ -54,11 +74,11 @@ function validate({ value, typeDefinition: { subtype } }: InputValidatorParams)
throw new Error(t('valueRequired'));
}
try {
JSON.parse(value.toString());
parseMap(value);
} catch (e) {
throw new Error(t('valueNotParse'));
}
const obj = JSON.parse(value.toString());
const obj = parseJSON(value);
if (!Object.keys(obj).length || !Object.keys(obj)[0].trim().length) {
throw new Error(t('valueKeyRequired'));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import { BlobDimensionality, SimpleType } from 'models/Common/types';
import { InputProps, InputType, InputTypeDefinition } from '../../types';
import {
collectionInputTypeDefinition,
mapInputTypeDefinition,
nestedCollectionInputTypeDefinition,
nestedMapInputTypeDefinition,
primitiveLiteral,
} from '../../__mocks__/utils';
import { literalNone } from '../constants';
Expand Down Expand Up @@ -34,6 +36,22 @@ function makeSimpleInput(typeDefinition: InputTypeDefinition, value: any): Input
return { ...baseInputProps, value, typeDefinition };
}

function makeMapInput(typeDefinition: InputTypeDefinition, value: string): InputProps {
return {
...baseInputProps,
value,
typeDefinition: mapInputTypeDefinition(typeDefinition),
};
}

function makeNestedMapInput(typeDefinition: InputTypeDefinition, value: string): InputProps {
return {
...baseInputProps,
value,
typeDefinition: nestedMapInputTypeDefinition(typeDefinition),
};
}

function makeCollectionInput(typeDefinition: InputTypeDefinition, value: string): InputProps {
return {
...baseInputProps,
Expand Down Expand Up @@ -66,6 +84,36 @@ describe('literalToInputValue', () => {
expect(literalToInputValue(inputTypes.none, literalNone())).toEqual(undefined));
});

describe('Map', () => {
literalToInputTestCases.map(([typeDefinition, input, output]) => {
it(`should correctly convert map of ${typeDefinition.type}: ${stringifyValue(input)}`, () => {
const map: Core.ILiteral = {
map: {
literals: { a: input },
},
};
const expectedString = stringifyValue({ a: output });
const result = literalToInputValue(mapInputTypeDefinition(typeDefinition), map);
expect(result).toEqual(expectedString);
});
});

it('should return empty for noneType literals', () => {
const map: Core.ILiteral = {
map: {
literals: { a: literalNone() },
},
};

const typeDefinition: InputTypeDefinition = {
literalType: { simple: Core.SimpleType.NONE },
type: InputType.None,
};

expect(literalToInputValue(mapInputTypeDefinition(typeDefinition), map)).toEqual('{}');
});
});

describe('Collections', () => {
literalToInputTestCases.map(([typeDefinition, input, output]) => {
it(`should correctly convert collection of ${typeDefinition.type}: ${stringifyValue(
Expand Down Expand Up @@ -128,6 +176,49 @@ describe('inputToLiteral', () => {
});
});

describe('Map', () => {
literalTestCases.map(([typeDefinition, input, output]) => {
let singleMapValue: any;
let nestedMapValue: any;
if (typeDefinition.type === InputType.Struct) {
const objValue = JSON.parse(input);
singleMapValue = stringifyValue({ a: objValue });
nestedMapValue = stringifyValue({ a: { b: objValue } });
} else if (['boolean', 'number'].includes(typeof input)) {
singleMapValue = `{"a":${input}}`;
nestedMapValue = `{"a":{"b":${input}}}`;
} else if (input == null) {
singleMapValue = '{"a":null}';
nestedMapValue = '{"a":{"b":null}}';
} else if (typeof input === 'string' || Long.isLong(input)) {
singleMapValue = `{"a":"${input}"}`;
nestedMapValue = `{"a":{"b":"${input}"}}`;
} else if (input instanceof Date) {
const dateString = input.toISOString();
singleMapValue = `{"a":"${dateString}"}`;
nestedMapValue = `{"a":{"b":"${dateString}"}}`;
} else {
const stringValue = stringifyValue(input);
singleMapValue = `{"a":${stringValue}}`;
nestedMapValue = `{"a":{"b":${stringValue}}}`;
}

it(`should correctly convert map of type ${
typeDefinition.type
}: ${singleMapValue} (${typeof input})`, () => {
const result = inputToLiteral(makeMapInput(typeDefinition, singleMapValue));
expect(result.map!.literals!.a).toEqual(output);
});

it(`should correctly convert nested map of type ${
typeDefinition.type
}: ${nestedMapValue} (${typeof input})`, () => {
const result = inputToLiteral(makeNestedMapInput(typeDefinition, nestedMapValue));
expect(result.map!.literals!.a.map!.literals!.b).toEqual(output);
});
});
});

describe('Collections', () => {
literalTestCases.map(([typeDefinition, input, output]) => {
let singleCollectionValue: any;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ export const inputTypes: Record<InputTypeKey, InputTypeDefinition> = {
literalType: {
mapValueType: { simple: Core.SimpleType.STRING },
},
subtype: {
literalType: { simple: Core.SimpleType.NONE },
type: InputType.None,
},
type: InputType.Map,
},
none: {
Expand Down Expand Up @@ -194,10 +198,6 @@ export const validityTestCases = {
Long.MIN_VALUE,
],
},
map: {
invalid: ['a', {}, true, new Date(), 1.1, 0 / 0, '1.1', '1a'],
valid: [{ a: '1' }, { a: [1, 2, 3] }, { a: { b: 'c' } }],
},
// schema is just a specialized string input, so it has the same validity cases as string
schema: { invalid: [123, true, new Date(), {}], valid: ['', 'abcdefg'] },
string: { invalid: [123, true, new Date(), {}], valid: ['', 'abcdefg'] },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,12 @@ export function typeIsSupported(typeDefinition: InputTypeDefinition): boolean {
case InputType.Schema:
case InputType.String:
case InputType.Struct:
case InputType.Map:
return true;
case InputType.Map:
if (!subtype) {
return false;
}
return typeIsSupported(subtype);
case InputType.Collection: {
if (!subtype) {
console.error('Unexpected missing subtype for collection input', typeDefinition);
Expand Down
9 changes: 9 additions & 0 deletions packages/zapp/console/src/components/common/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ const str = {
serviceAccountHeader: 'Service Account',
noMatchingResults: 'No matching results',
missingMapSubType: 'Unexpected missing subtype for map',
mapMissingMapProperty: 'Map literal missing `map` property',
mapMissingMapLiteralsProperty: 'Map literal missing `map.literals` property',
mapLiternalNotObject: 'Map literal is not an object',
mapLiternalObjectEmpty: 'Map literal object is empty',
valueNotString: 'Value is not a string',
valueRequired: 'Value is required',
valueNotParse: 'Value did not parse to an object',
valueKeyRequired: "Value's key is required",
valueValueInvalid: "Value's value is invalid",
};

export { patternKey } from '@flyteconsole/locale';
Expand Down

0 comments on commit 7eaeb78

Please sign in to comment.