Skip to content

Commit 87a9c94

Browse files
tohlhRichDom2185
andauthored
Language options (#1757)
* Add language options, any checker and tests * Use Record instead of Map * Added tests for any checker * Added tests for type declaration * Fix incorrect merge conflict resolution * Fix incorrect test cases initialization * Fix compile errors post-merge * Fix line number shift --------- Co-authored-by: Richard Dominick <34370238+RichDom2185@users.noreply.github.com>
1 parent 28d6c02 commit 87a9c94

File tree

2 files changed

+331
-4
lines changed

2 files changed

+331
-4
lines changed
Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
import { parseError } from '../../index'
2+
import { SourceTypedParser } from '../../parser/source/typed'
3+
import { Chapter, type LanguageOptions, Variant } from '../../types'
4+
import { mockContext } from '../../utils/testing/mocks'
5+
6+
const parser = new SourceTypedParser(Chapter.SOURCE_4, Variant.TYPED)
7+
8+
describe('Any checker tests', () => {
9+
test('disallow any type in a variable declaration', () => {
10+
const languageOptions: LanguageOptions = {}
11+
languageOptions['typedAllowAnyInVariables'] = 'false'
12+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
13+
parser.parse('const x = 4;', localContext)
14+
expect(parseError(localContext.errors)).toEqual(
15+
'Line 1: Usage of "any" in variable declaration is not allowed.'
16+
)
17+
})
18+
19+
test('allow any type in a variable declaration', () => {
20+
const languageOptions: LanguageOptions = {}
21+
languageOptions['typedAllowAnyInVariables'] = 'true'
22+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
23+
parser.parse('let x: any = 4;', localContext)
24+
expect(parseError(localContext.errors)).toEqual('')
25+
})
26+
27+
test('allow any type in a variable declaration, correct declaration', () => {
28+
const languageOptions: LanguageOptions = {}
29+
languageOptions['typedAllowAnyInVariables'] = 'false'
30+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
31+
parser.parse('let x: number = 4;', localContext)
32+
expect(parseError(localContext.errors)).toEqual('')
33+
})
34+
35+
test('disallow any type in function parameter', () => {
36+
const languageOptions: LanguageOptions = {}
37+
languageOptions['typedAllowAnyInParameters'] = 'false'
38+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
39+
parser.parse('function f(x: any) { return x; }', localContext)
40+
expect(parseError(localContext.errors)).toEqual(
41+
'Line 1: Usage of "any" in function parameter is not allowed.'
42+
)
43+
})
44+
45+
test('allow any type in function parameter', () => {
46+
const languageOptions: LanguageOptions = {}
47+
languageOptions['typedAllowAnyInParameters'] = 'true'
48+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
49+
parser.parse('function f(x: any) { return x; }', localContext)
50+
expect(parseError(localContext.errors)).toEqual('')
51+
})
52+
53+
test('allow any type in function parameter, correct declaration', () => {
54+
const languageOptions: LanguageOptions = {}
55+
languageOptions['typedAllowAnyInParameters'] = 'false'
56+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
57+
parser.parse('function f(x: number) { return x; }', localContext)
58+
expect(parseError(localContext.errors)).toEqual('')
59+
})
60+
61+
test('disallow any type in function return type', () => {
62+
const languageOptions: LanguageOptions = {}
63+
languageOptions['typedAllowAnyInReturnType'] = 'true'
64+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
65+
parser.parse('function g(): any { return 4; }', localContext)
66+
expect(parseError(localContext.errors)).toEqual('')
67+
})
68+
69+
test('allow any type in function return type', () => {
70+
const languageOptions: LanguageOptions = {}
71+
languageOptions['typedAllowAnyInReturnType'] = 'false'
72+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
73+
parser.parse('function g(): any { return 4; }', localContext)
74+
expect(parseError(localContext.errors)).toEqual(
75+
'Line 1: Usage of "any" in function return type is not allowed.'
76+
)
77+
})
78+
79+
test('allow any type in function return type, correct declaration', () => {
80+
const languageOptions: LanguageOptions = {}
81+
languageOptions['typedAllowAnyInReturnType'] = 'false'
82+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
83+
parser.parse('function g(): number { return 4; }', localContext)
84+
expect(parseError(localContext.errors)).toEqual('')
85+
})
86+
87+
test('disallow any type in lambda parameter', () => {
88+
const languageOptions: LanguageOptions = {}
89+
languageOptions['typedAllowAnyInParameters'] = 'false'
90+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
91+
parser.parse('const h = (x: any) => x + 1;', localContext)
92+
expect(parseError(localContext.errors)).toEqual(
93+
'Line 1: Usage of "any" in arrow function parameter is not allowed.'
94+
)
95+
})
96+
97+
test('allow any type in lambda parameter', () => {
98+
const languageOptions: LanguageOptions = {}
99+
languageOptions['typedAllowAnyInParameters'] = 'true'
100+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
101+
parser.parse('const h = (x: any) => x + 1;', localContext)
102+
expect(parseError(localContext.errors)).toEqual('')
103+
})
104+
105+
test('allow any type in lambda parameter, correct declaration', () => {
106+
const languageOptions: LanguageOptions = {}
107+
languageOptions['typedAllowAnyInParameters'] = 'false'
108+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
109+
parser.parse('const h = (x: number) => x + 1;', localContext)
110+
expect(parseError(localContext.errors)).toEqual('')
111+
})
112+
113+
test('disallow any type in nested lambda', () => {
114+
const languageOptions: LanguageOptions = {}
115+
languageOptions['typedAllowAnyInParameters'] = 'false'
116+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
117+
parser.parse('const f = (x: number) => (y: any) => x + y;', localContext)
118+
expect(parseError(localContext.errors)).toEqual(
119+
'Line 1: Usage of "any" in arrow function parameter is not allowed.'
120+
)
121+
})
122+
123+
test('allow any type in nested lambda', () => {
124+
const languageOptions: LanguageOptions = {}
125+
languageOptions['typedAllowAnyInParameters'] = 'true'
126+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
127+
parser.parse('const f = (x: number) => (y: any) => x + y;', localContext)
128+
expect(parseError(localContext.errors)).toEqual('')
129+
})
130+
131+
test('allow any type in nested lambda, correct declaration', () => {
132+
const languageOptions: LanguageOptions = {}
133+
languageOptions['typedAllowAnyInParameters'] = 'false'
134+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
135+
parser.parse('const f = (x: number) => (y: number) => x + y;', localContext)
136+
expect(parseError(localContext.errors)).toEqual('')
137+
})
138+
139+
test('allow any type in nested function', () => {
140+
const languageOptions: LanguageOptions = {}
141+
languageOptions['typedAllowAnyInParameters'] = 'true'
142+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
143+
parser.parse(
144+
`
145+
function f(x: number) {
146+
function g(y: any) {
147+
return x + y;
148+
}
149+
return g;
150+
}
151+
`,
152+
localContext
153+
)
154+
expect(parseError(localContext.errors)).toEqual('')
155+
})
156+
157+
test('disallow any type in nested function', () => {
158+
const languageOptions: LanguageOptions = {}
159+
languageOptions['typedAllowAnyInParameters'] = 'false'
160+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
161+
parser.parse(
162+
`
163+
function f(x: number) {
164+
function g(y: any) {
165+
return x + y;
166+
}
167+
return g;
168+
}
169+
`,
170+
localContext
171+
)
172+
expect(parseError(localContext.errors)).toEqual(
173+
'Line 3: Usage of "any" in function parameter is not allowed.'
174+
)
175+
})
176+
177+
test('allow any type in nested function, correct declaration', () => {
178+
const languageOptions: LanguageOptions = {}
179+
languageOptions['typedAllowAnyInParameters'] = 'false'
180+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
181+
parser.parse(
182+
`
183+
function f(x: number) : (y: number) => number {
184+
function g(y: number) {
185+
return x + y;
186+
}
187+
return g;
188+
}
189+
`,
190+
localContext
191+
)
192+
expect(parseError(localContext.errors)).toEqual('')
193+
})
194+
195+
test('allow any type in type annotation parameters', () => {
196+
const languageOptions: LanguageOptions = {}
197+
languageOptions['typedAllowAnyInTypeAnnotationParameters'] = 'true'
198+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
199+
parser.parse(
200+
`
201+
function f(x: number) : (y: any) => number {
202+
function g(y: number) {
203+
return x + y;
204+
}
205+
return g;
206+
}
207+
`,
208+
localContext
209+
)
210+
expect(parseError(localContext.errors)).toEqual('')
211+
})
212+
213+
test('disallow any type in type annotation parameters', () => {
214+
const languageOptions: LanguageOptions = {}
215+
languageOptions['typedAllowAnyInTypeAnnotationParameters'] = 'false'
216+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
217+
parser.parse(
218+
`
219+
function f(x: number) : (y: any) => number {
220+
function g(y: number) {
221+
return x + y;
222+
}
223+
return g;
224+
}
225+
`,
226+
localContext
227+
)
228+
expect(parseError(localContext.errors)).toEqual(
229+
'Line 2: Usage of "any" in type annotation\'s function parameter is not allowed.'
230+
)
231+
})
232+
233+
test('disallow any type in type annotation parameters, correct declaration', () => {
234+
const languageOptions: LanguageOptions = {}
235+
languageOptions['typedAllowAnyInTypeAnnotationParameters'] = 'false'
236+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
237+
parser.parse(
238+
`
239+
function f(x: number) : (y: number) => number {
240+
function g(y: number) {
241+
return x + y;
242+
}
243+
return g;
244+
}
245+
`,
246+
localContext
247+
)
248+
expect(parseError(localContext.errors)).toEqual('')
249+
})
250+
251+
test('allow any type in type annotation return type', () => {
252+
const languageOptions: LanguageOptions = {}
253+
languageOptions['typedAllowAnyInTypeAnnotationReturnType'] = 'true'
254+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
255+
parser.parse(
256+
`
257+
function f(x: number) {
258+
function g(y: number) : any {
259+
return x + y;
260+
}
261+
return g;
262+
}
263+
`,
264+
localContext
265+
)
266+
expect(parseError(localContext.errors)).toEqual('')
267+
})
268+
269+
test('disallow any type in type annotation return type', () => {
270+
const languageOptions: LanguageOptions = {}
271+
languageOptions['typedAllowAnyInTypeAnnotationReturnType'] = 'false'
272+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
273+
parser.parse(
274+
`
275+
function f(x: number) : (y: number) => any {
276+
function g(y: number) : number {
277+
return x + y;
278+
}
279+
return g;
280+
}
281+
`,
282+
localContext
283+
)
284+
expect(parseError(localContext.errors)).toEqual(
285+
'Line 2: Usage of "any" in type annotation\'s function return type is not allowed.'
286+
)
287+
})
288+
289+
test('disallow any type in type annotation return type, correct declaration', () => {
290+
const languageOptions: LanguageOptions = {}
291+
languageOptions['typedAllowAnyInTypeAnnotationReturnType'] = 'false'
292+
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
293+
parser.parse(
294+
`
295+
function f(x: number) : (y: number) => number {
296+
function g(y: number) : number {
297+
return x + y;
298+
}
299+
return g;
300+
}
301+
`,
302+
localContext
303+
)
304+
expect(parseError(localContext.errors)).toEqual('')
305+
})
306+
})

src/typeChecker/__tests__/source4TypedModules.test.ts

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { mockContext } from '../../utils/testing/mocks'
2-
import { Chapter, Variant } from '../../types'
3-
import { parse } from '../../parser/parser'
41
import { parseError } from '../../index'
2+
import { parse } from '../../parser/parser'
3+
import { Chapter, Variant } from '../../types'
4+
import { mockContext } from '../../utils/testing/mocks'
55

66
function getContext() {
77
const context = mockContext(Chapter.SOURCE_4, Variant.TYPED)
@@ -14,6 +14,8 @@ function getContext() {
1414
class Test1 {}
1515
class Test2 {}
1616
class Test3 {}
17+
type Test4 = (arg: Test1) => Test2;
18+
const Test4 = (arg: Test1) => Test2;
1719
`,
1820
x: 'const x: string = "hello"',
1921
y: 'const y: number = 42',
@@ -179,7 +181,7 @@ describe('Typed module tests', () => {
179181
const a: string = functionError(10);
180182
`
181183
expect(testParseError(code)).toMatchInlineSnapshot(
182-
`"Line 6: Type 'number' is not assignable to type 'string'."`
184+
`"Line 8: Type 'number' is not assignable to type 'string'."`
183185
)
184186
})
185187

@@ -261,4 +263,23 @@ describe('Typed module tests', () => {
261263
)
262264
})
263265
})
266+
267+
/* TEST CASES FOR THE 'Test4' TYPE */
268+
it('should allow calling Test4 with a valid Test1 object', () => {
269+
const code = `
270+
import { test2 } from 'exampleModule';
271+
const result: Test4 = (arg: Test1) => test2;
272+
`
273+
expect(testParseError(code)).toMatchInlineSnapshot(`""`)
274+
})
275+
276+
it('should error when calling Test4 with a string argument', () => {
277+
const code = `
278+
import { test1 } from 'exampleModule';
279+
const result: Test4 = (arg: Test1) => test1;
280+
`
281+
expect(testParseError(code)).toMatchInlineSnapshot(
282+
`"Line 3: Type '(Test1) => Test1' is not assignable to type 'Test4'."`
283+
)
284+
})
264285
})

0 commit comments

Comments
 (0)