Skip to content
Merged
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
306 changes: 306 additions & 0 deletions src/typeChecker/__tests__/source4TypedAnyChecker.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,306 @@
import { parseError } from '../../index'
import { SourceTypedParser } from '../../parser/source/typed'
import { Chapter, type LanguageOptions, Variant } from '../../types'
import { mockContext } from '../../utils/testing/mocks'

const parser = new SourceTypedParser(Chapter.SOURCE_4, Variant.TYPED)

describe('Any checker tests', () => {
test('disallow any type in a variable declaration', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInVariables'] = 'false'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse('const x = 4;', localContext)
expect(parseError(localContext.errors)).toEqual(
'Line 1: Usage of "any" in variable declaration is not allowed.'
)
})

test('allow any type in a variable declaration', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInVariables'] = 'true'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse('let x: any = 4;', localContext)
expect(parseError(localContext.errors)).toEqual('')
})

test('allow any type in a variable declaration, correct declaration', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInVariables'] = 'false'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse('let x: number = 4;', localContext)
expect(parseError(localContext.errors)).toEqual('')
})

test('disallow any type in function parameter', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInParameters'] = 'false'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse('function f(x: any) { return x; }', localContext)
expect(parseError(localContext.errors)).toEqual(
'Line 1: Usage of "any" in function parameter is not allowed.'
)
})

test('allow any type in function parameter', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInParameters'] = 'true'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse('function f(x: any) { return x; }', localContext)
expect(parseError(localContext.errors)).toEqual('')
})

test('allow any type in function parameter, correct declaration', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInParameters'] = 'false'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse('function f(x: number) { return x; }', localContext)
expect(parseError(localContext.errors)).toEqual('')
})

test('disallow any type in function return type', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInReturnType'] = 'true'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse('function g(): any { return 4; }', localContext)
expect(parseError(localContext.errors)).toEqual('')
})

test('allow any type in function return type', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInReturnType'] = 'false'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse('function g(): any { return 4; }', localContext)
expect(parseError(localContext.errors)).toEqual(
'Line 1: Usage of "any" in function return type is not allowed.'
)
})

test('allow any type in function return type, correct declaration', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInReturnType'] = 'false'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse('function g(): number { return 4; }', localContext)
expect(parseError(localContext.errors)).toEqual('')
})

test('disallow any type in lambda parameter', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInParameters'] = 'false'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse('const h = (x: any) => x + 1;', localContext)
expect(parseError(localContext.errors)).toEqual(
'Line 1: Usage of "any" in arrow function parameter is not allowed.'
)
})

test('allow any type in lambda parameter', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInParameters'] = 'true'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse('const h = (x: any) => x + 1;', localContext)
expect(parseError(localContext.errors)).toEqual('')
})

test('allow any type in lambda parameter, correct declaration', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInParameters'] = 'false'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse('const h = (x: number) => x + 1;', localContext)
expect(parseError(localContext.errors)).toEqual('')
})

test('disallow any type in nested lambda', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInParameters'] = 'false'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse('const f = (x: number) => (y: any) => x + y;', localContext)
expect(parseError(localContext.errors)).toEqual(
'Line 1: Usage of "any" in arrow function parameter is not allowed.'
)
})

test('allow any type in nested lambda', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInParameters'] = 'true'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse('const f = (x: number) => (y: any) => x + y;', localContext)
expect(parseError(localContext.errors)).toEqual('')
})

test('allow any type in nested lambda, correct declaration', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInParameters'] = 'false'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse('const f = (x: number) => (y: number) => x + y;', localContext)
expect(parseError(localContext.errors)).toEqual('')
})

test('allow any type in nested function', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInParameters'] = 'true'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse(
`
function f(x: number) {
function g(y: any) {
return x + y;
}
return g;
}
`,
localContext
)
expect(parseError(localContext.errors)).toEqual('')
})

test('disallow any type in nested function', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInParameters'] = 'false'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse(
`
function f(x: number) {
function g(y: any) {
return x + y;
}
return g;
}
`,
localContext
)
expect(parseError(localContext.errors)).toEqual(
'Line 3: Usage of "any" in function parameter is not allowed.'
)
})

test('allow any type in nested function, correct declaration', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInParameters'] = 'false'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse(
`
function f(x: number) : (y: number) => number {
function g(y: number) {
return x + y;
}
return g;
}
`,
localContext
)
expect(parseError(localContext.errors)).toEqual('')
})

test('allow any type in type annotation parameters', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInTypeAnnotationParameters'] = 'true'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse(
`
function f(x: number) : (y: any) => number {
function g(y: number) {
return x + y;
}
return g;
}
`,
localContext
)
expect(parseError(localContext.errors)).toEqual('')
})

test('disallow any type in type annotation parameters', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInTypeAnnotationParameters'] = 'false'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse(
`
function f(x: number) : (y: any) => number {
function g(y: number) {
return x + y;
}
return g;
}
`,
localContext
)
expect(parseError(localContext.errors)).toEqual(
'Line 2: Usage of "any" in type annotation\'s function parameter is not allowed.'
)
})

test('disallow any type in type annotation parameters, correct declaration', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInTypeAnnotationParameters'] = 'false'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse(
`
function f(x: number) : (y: number) => number {
function g(y: number) {
return x + y;
}
return g;
}
`,
localContext
)
expect(parseError(localContext.errors)).toEqual('')
})

test('allow any type in type annotation return type', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInTypeAnnotationReturnType'] = 'true'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse(
`
function f(x: number) {
function g(y: number) : any {
return x + y;
}
return g;
}
`,
localContext
)
expect(parseError(localContext.errors)).toEqual('')
})

test('disallow any type in type annotation return type', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInTypeAnnotationReturnType'] = 'false'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse(
`
function f(x: number) : (y: number) => any {
function g(y: number) : number {
return x + y;
}
return g;
}
`,
localContext
)
expect(parseError(localContext.errors)).toEqual(
'Line 2: Usage of "any" in type annotation\'s function return type is not allowed.'
)
})

test('disallow any type in type annotation return type, correct declaration', () => {
const languageOptions: LanguageOptions = {}
languageOptions['typedAllowAnyInTypeAnnotationReturnType'] = 'false'
const localContext = mockContext(Chapter.SOURCE_4, Variant.TYPED, languageOptions)
parser.parse(
`
function f(x: number) : (y: number) => number {
function g(y: number) : number {
return x + y;
}
return g;
}
`,
localContext
)
expect(parseError(localContext.errors)).toEqual('')
})
})
29 changes: 25 additions & 4 deletions src/typeChecker/__tests__/source4TypedModules.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { mockContext } from '../../utils/testing/mocks'
import { Chapter, Variant } from '../../types'
import { parse } from '../../parser/parser'
import { parseError } from '../../index'
import { parse } from '../../parser/parser'
import { Chapter, Variant } from '../../types'
import { mockContext } from '../../utils/testing/mocks'

function getContext() {
const context = mockContext(Chapter.SOURCE_4, Variant.TYPED)
Expand All @@ -14,6 +14,8 @@ function getContext() {
class Test1 {}
class Test2 {}
class Test3 {}
type Test4 = (arg: Test1) => Test2;
const Test4 = (arg: Test1) => Test2;
`,
x: 'const x: string = "hello"',
y: 'const y: number = 42',
Expand Down Expand Up @@ -179,7 +181,7 @@ describe('Typed module tests', () => {
const a: string = functionError(10);
`
expect(testParseError(code)).toMatchInlineSnapshot(
`"Line 6: Type 'number' is not assignable to type 'string'."`
`"Line 8: Type 'number' is not assignable to type 'string'."`
)
})

Expand Down Expand Up @@ -261,4 +263,23 @@ describe('Typed module tests', () => {
)
})
})

/* TEST CASES FOR THE 'Test4' TYPE */
it('should allow calling Test4 with a valid Test1 object', () => {
const code = `
import { test2 } from 'exampleModule';
const result: Test4 = (arg: Test1) => test2;
`
expect(testParseError(code)).toMatchInlineSnapshot(`""`)
})

it('should error when calling Test4 with a string argument', () => {
const code = `
import { test1 } from 'exampleModule';
const result: Test4 = (arg: Test1) => test1;
`
expect(testParseError(code)).toMatchInlineSnapshot(
`"Line 3: Type '(Test1) => Test1' is not assignable to type 'Test4'."`
)
})
})
Loading