blob: a61d0edaca0d7104ebae6f11a661ebe273d6a798 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:io' as io;
import 'package:header_guard_check/src/header_file.dart';
import 'package:litetest/litetest.dart';
import 'package:path/path.dart' as p;
import 'package:source_span/source_span.dart';
Future<int> main(List<String> args) async {
void withTestFile(String path, String contents, void Function(io.File) fn) {
// Create a temporary file and delete it when we're done.
final io.Directory tempDir = io.Directory.systemTemp.createTempSync('header_guard_check_test');
final io.File file = io.File(p.join(tempDir.path, path));
file.writeAsStringSync(contents);
try {
fn(file);
} finally {
tempDir.deleteSync(recursive: true);
}
}
group('HeaderGuardSpans', () {
test('parses #ifndef', () {
const String input = '#ifndef FOO_H_';
final HeaderGuardSpans guard = HeaderGuardSpans(
ifndefSpan: SourceSpanWithContext(
SourceLocation(0),
SourceLocation(input.length),
input,
input,
),
defineSpan: null,
endifSpan: null,
);
expect(guard.ifndefValue, 'FOO_H_');
});
test('ignores #ifndef if omitted', () {
const HeaderGuardSpans guard = HeaderGuardSpans(
ifndefSpan: null,
defineSpan: null,
endifSpan: null,
);
expect(guard.ifndefValue, isNull);
});
test('ignores #ifndef if invalid', () {
const String input = '#oops FOO_H_';
final HeaderGuardSpans guard = HeaderGuardSpans(
ifndefSpan: SourceSpanWithContext(
SourceLocation(0),
SourceLocation(input.length),
input,
input,
),
defineSpan: null,
endifSpan: null,
);
expect(guard.ifndefValue, isNull);
});
test('parses #define', () {
const String input = '#define FOO_H_';
final HeaderGuardSpans guard = HeaderGuardSpans(
ifndefSpan: null,
defineSpan: SourceSpanWithContext(
SourceLocation(0),
SourceLocation(input.length),
input,
input,
),
endifSpan: null,
);
expect(guard.defineValue, 'FOO_H_');
});
test('ignores #define if omitted', () {
const HeaderGuardSpans guard = HeaderGuardSpans(
ifndefSpan: null,
defineSpan: null,
endifSpan: null,
);
expect(guard.defineValue, isNull);
});
test('ignores #define if invalid', () {
const String input = '#oops FOO_H_';
final HeaderGuardSpans guard = HeaderGuardSpans(
ifndefSpan: null,
defineSpan: SourceSpanWithContext(
SourceLocation(0),
SourceLocation(input.length),
input,
input,
),
endifSpan: null,
);
expect(guard.defineValue, isNull);
});
test('parses #endif', () {
const String input = '#endif // FOO_H_';
final HeaderGuardSpans guard = HeaderGuardSpans(
ifndefSpan: null,
defineSpan: null,
endifSpan: SourceSpanWithContext(
SourceLocation(0),
SourceLocation(input.length),
input,
input,
),
);
expect(guard.endifValue, 'FOO_H_');
});
test('ignores #endif if omitted', () {
const HeaderGuardSpans guard = HeaderGuardSpans(
ifndefSpan: null,
defineSpan: null,
endifSpan: null,
);
expect(guard.endifValue, isNull);
});
test('ignores #endif if invalid', () {
const String input = '#oops // FOO_H_';
final HeaderGuardSpans guard = HeaderGuardSpans(
ifndefSpan: null,
defineSpan: null,
endifSpan: SourceSpanWithContext(
SourceLocation(0),
SourceLocation(input.length),
input,
input,
),
);
expect(guard.endifValue, isNull);
});
});
group('HeaderFile', () {
test('produces a valid header guard name from various file names', () {
// All of these should produce the name `FOO_BAR_BAZ_H_`.
const List<String> inputs = <String>[
'foo_bar_baz.h',
'foo-bar-baz.h',
'foo_bar-baz.h',
'foo-bar_baz.h',
'foo+bar+baz.h',
];
for (final String input in inputs) {
final HeaderFile headerFile = HeaderFile.from(
input,
guard: null,
pragmaOnce: null,
);
expect(headerFile.computeExpectedName(engineRoot: ''), endsWith('FOO_BAR_BAZ_H_'));
}
});
test('parses a header file with a valid guard', () {
final String input = <String>[
'#ifndef FOO_H_',
'#define FOO_H_',
'',
'#endif // FOO_H_',
].join('\n');
withTestFile('foo.h', input, (io.File file) {
final HeaderFile headerFile = HeaderFile.parse(file.path);
expect(headerFile.guard!.ifndefValue, 'FOO_H_');
expect(headerFile.guard!.defineValue, 'FOO_H_');
expect(headerFile.guard!.endifValue, 'FOO_H_');
});
});
test('parses a header file with an invalid #endif', () {
final String input = <String>[
'#ifndef FOO_H_',
'#define FOO_H_',
'',
// No comment after the #endif.
'#endif',
].join('\n');
withTestFile('foo.h', input, (io.File file) {
final HeaderFile headerFile = HeaderFile.parse(file.path);
expect(headerFile.guard!.ifndefValue, 'FOO_H_');
expect(headerFile.guard!.defineValue, 'FOO_H_');
expect(headerFile.guard!.endifValue, isNull);
});
});
test('parses a header file with a missing #define', () {
final String input = <String>[
'#ifndef FOO_H_',
// No #define.
'',
'#endif // FOO_H_',
].join('\n');
withTestFile('foo.h', input, (io.File file) {
final HeaderFile headerFile = HeaderFile.parse(file.path);
expect(headerFile.guard!.ifndefValue, 'FOO_H_');
expect(headerFile.guard!.defineValue, isNull);
expect(headerFile.guard!.endifValue, 'FOO_H_');
});
});
test('parses a header file with a missing #ifndef', () {
final String input = <String>[
// No #ifndef.
'#define FOO_H_',
'',
'#endif // FOO_H_',
].join('\n');
withTestFile('foo.h', input, (io.File file) {
final HeaderFile headerFile = HeaderFile.parse(file.path);
expect(headerFile.guard, isNull);
});
});
test('parses a header file with a #pragma once', () {
final String input = <String>[
'#pragma once',
'',
].join('\n');
withTestFile('foo.h', input, (io.File file) {
final HeaderFile headerFile = HeaderFile.parse(file.path);
expect(headerFile.pragmaOnce, isNotNull);
});
});
test('fixes a file that uses #pragma once', () {
final String input = <String>[
'#pragma once',
'',
'// ...',
].join('\n');
withTestFile('foo.h', input, (io.File file) {
final HeaderFile headerFile = HeaderFile.parse(file.path);
expect(headerFile.fix(engineRoot: p.dirname(file.path)), isTrue);
expect(file.readAsStringSync(), <String>[
'#ifndef FLUTTER_FOO_H_',
'#define FLUTTER_FOO_H_',
'',
'// ...',
'#endif // FLUTTER_FOO_H_',
'',
].join('\n'));
});
});
test('fixes a file with an incorrect header guard', () {
final String input = <String>[
'#ifndef FOO_H_',
'#define FOO_H_',
'',
'#endif // FOO_H_',
].join('\n');
withTestFile('foo.h', input, (io.File file) {
final HeaderFile headerFile = HeaderFile.parse(file.path);
expect(headerFile.fix(engineRoot: p.dirname(file.path)), isTrue);
expect(file.readAsStringSync(), <String>[
'#ifndef FLUTTER_FOO_H_',
'#define FLUTTER_FOO_H_',
'',
'#endif // FLUTTER_FOO_H_',
'',
].join('\n'));
});
});
test('fixes a file with no header guard', () {
final String input = <String>[
'// 1.',
'// 2.',
'// 3.',
'',
"#import 'flutter/shell/platform/darwin/Flutter.h'",
'',
'@protocl Flutter',
'',
'@end',
'',
].join('\n');
withTestFile('foo.h', input, (io.File file) {
final HeaderFile headerFile = HeaderFile.parse(file.path);
expect(headerFile.fix(engineRoot: p.dirname(file.path)), isTrue);
expect(file.readAsStringSync(), <String>[
'// 1.',
'// 2.',
'// 3.',
'',
'#ifndef FLUTTER_FOO_H_',
'#define FLUTTER_FOO_H_',
'',
"#import 'flutter/shell/platform/darwin/Flutter.h'",
'',
'@protocl Flutter',
'',
'@end',
'',
'#endif // FLUTTER_FOO_H_',
'',
].join('\n'));
});
});
test('does not touch a file with an existing guard and another #define', () {
final String input = <String>[
'// 1.',
'// 2.',
'// 3.',
'',
'#define FML_USED_ON_EMBEDDER',
'',
'#ifndef FLUTTER_FOO_H_',
'#define FLUTTER_FOO_H_',
'',
'#endif // FLUTTER_FOO_H_',
'',
].join('\n');
withTestFile('foo.h', input, (io.File file) {
final HeaderFile headerFile = HeaderFile.parse(file.path);
expect(headerFile.fix(engineRoot: p.dirname(file.path)), isFalse);
});
});
test('is OK with windows-style CRLF file with a valid header guard', () {
final String input = <String>[
'#ifndef FLUTTER_FOO_H_',
'#define FLUTTER_FOO_H_',
'',
'// ...',
'',
'#endif // FLUTTER_FOO_H_',
].join('\r\n');
withTestFile('foo.h', input, (io.File file) {
final HeaderFile headerFile = HeaderFile.parse(file.path);
expect(headerFile.pragmaOnce, isNull);
expect(headerFile.guard!.ifndefValue, 'FLUTTER_FOO_H_');
expect(headerFile.guard!.defineValue, 'FLUTTER_FOO_H_');
expect(headerFile.guard!.endifValue, 'FLUTTER_FOO_H_');
});
});
});
return 0;
}