Skip to content

Commit 973bc55

Browse files
committed
Begin mocking and migration
1 parent 50d2210 commit 973bc55

File tree

11 files changed

+2681
-100
lines changed

11 files changed

+2681
-100
lines changed

openapi-generator/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.PHONY: gen
2+
3+
gen:
4+
dart run build_runner build --delete-conflicting-outputs

openapi-generator/lib/src/openapi_generator_runner.dart

Lines changed: 71 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -37,51 +37,28 @@ class OpenapiGenerator extends GeneratorForAnnotation<annots.Openapi> {
3737
),
3838
);
3939

40-
try {
41-
if (element is! ClassElement) {
42-
final friendlyName = element.displayName;
43-
44-
throw InvalidGenerationSourceError(
45-
'Generator cannot target `$friendlyName`.',
46-
todo: 'Remove the [Openapi] annotation from `$friendlyName`.',
47-
);
48-
} else {
49-
if (!(annotations.read('useNextGen').literalValue as bool)) {
50-
if (annotations.read('cachePath').literalValue != null) {
51-
throw InvalidGenerationSourceError(
52-
'useNextGen must be set when using cachePath',
53-
todo:
54-
'Either set useNextGen: true on the annotation or remove the custom cachePath',
55-
);
56-
}
57-
}
40+
if (element is! ClassElement) {
41+
final friendlyName = element.displayName;
5842

43+
throw InvalidGenerationSourceError(
44+
'Generator cannot target `$friendlyName`.',
45+
todo: 'Remove the [Openapi] annotation from `$friendlyName`.',
46+
);
47+
} else {
48+
if (!(annotations.read('useNextGen').literalValue as bool) &&
49+
annotations.read('cachePath').literalValue != null) {
50+
throw AssertionError('useNextGen must be set when using cachePath');
51+
}
52+
try {
5953
// Transform the annotations.
6054
final args = GeneratorArguments(annotations: annotations);
61-
6255
// Determine if the project has a dependency on the flutter sdk or not.
6356
final baseCommand = await checkPubspecAndWrapperForFlutterSupport(
6457
wrapper: args.wrapper, providedPubspecPath: args.pubspecPath)
6558
? 'flutter'
6659
: 'dart';
6760

68-
if (!args.useNextGen) {
69-
final path =
70-
'${args.outputDirectory}${Platform.pathSeparator}lib${Platform.pathSeparator}api.dart';
71-
if (await File(path).exists()) {
72-
if (!args.alwaysRun) {
73-
logOutputMessage(
74-
log: log,
75-
communication: OutputMessage(
76-
message:
77-
'Generated client already exists at [$path] and configuration is annotated with alwaysRun: [${args.alwaysRun}]. Therefore, skipping this build. Note that the "alwaysRun" config will be removed in future versions.',
78-
level: Level.INFO,
79-
),
80-
);
81-
return '';
82-
}
83-
}
84-
} else {
61+
if (args.useNextGen) {
8562
// If the flag to use the next generation of the generator is applied
8663
// use the new functionality.
8764
return generatorV2(
@@ -90,26 +67,42 @@ class OpenapiGenerator extends GeneratorForAnnotation<annots.Openapi> {
9067
annotatedPath: buildStep.inputId.path);
9168
}
9269

70+
final path =
71+
'${args.outputDirectory}${Platform.pathSeparator}lib${Platform.pathSeparator}api.dart';
72+
if (await File(path).exists()) {
73+
if (!args.alwaysRun) {
74+
logOutputMessage(
75+
log: log,
76+
communication: OutputMessage(
77+
message:
78+
'Generated client already exists at [$path] and configuration is annotated with alwaysRun: [${args.alwaysRun}]. Therefore, skipping this build. Note that the "alwaysRun" config will be removed in future versions.',
79+
level: Level.INFO,
80+
),
81+
);
82+
return '';
83+
}
84+
}
85+
9386
await runOpenApiJar(arguments: args);
9487
await fetchDependencies(baseCommand: baseCommand, args: args);
9588
await generateSources(baseCommand: baseCommand, args: args);
96-
}
97-
} catch (e, st) {
98-
late OutputMessage communication;
99-
if (e is! OutputMessage) {
100-
communication = OutputMessage(
101-
message: '- There was an error generating the spec.',
102-
level: Level.SEVERE,
103-
additionalContext: e,
104-
stackTrace: st,
105-
);
106-
} else {
107-
communication = e;
108-
}
89+
} catch (e, st) {
90+
late OutputMessage communication;
91+
if (e is! OutputMessage) {
92+
communication = OutputMessage(
93+
message: '- There was an error generating the spec.',
94+
level: Level.SEVERE,
95+
additionalContext: e,
96+
stackTrace: st,
97+
);
98+
} else {
99+
communication = e;
100+
}
109101

110-
logOutputMessage(log: log, communication: communication);
102+
logOutputMessage(log: log, communication: communication);
103+
}
104+
return '';
111105
}
112-
return '';
113106
}
114107

115108
/// Runs the OpenAPI compiler with the given [args].
@@ -130,23 +123,18 @@ class OpenapiGenerator extends GeneratorForAnnotation<annots.Openapi> {
130123
// Include java environment variables in openApiCliCommand
131124
var javaOpts = Platform.environment['JAVA_OPTS'] ?? '';
132125

133-
ProcessResult result;
134-
if (!testMode) {
135-
result = await Process.run(
136-
'java',
137-
[
126+
final result = await runExternalProcess(
127+
command: Command(
128+
executable: 'java',
129+
arguments: [
138130
if (javaOpts.isNotEmpty) javaOpts,
139131
'-jar',
140132
binPath,
141133
...args,
142134
],
143-
workingDirectory: Directory.current.path,
144-
runInShell: Platform.isWindows,
145-
);
146-
} else {
147-
result = ProcessResult(999999, 0, null, null);
148-
}
149-
135+
),
136+
workingDirectory: Directory.current.path,
137+
);
150138
if (result.exitCode != 0) {
151139
return Future.error(
152140
OutputMessage(
@@ -359,17 +347,8 @@ class OpenapiGenerator extends GeneratorForAnnotation<annots.Openapi> {
359347
),
360348
);
361349

362-
ProcessResult results;
363-
if (!testMode) {
364-
results = await Process.run(
365-
command.executable,
366-
command.arguments,
367-
runInShell: Platform.isWindows,
368-
workingDirectory: args.outputDirectory,
369-
);
370-
} else {
371-
results = ProcessResult(99999, 0, null, null);
372-
}
350+
final results = await runExternalProcess(
351+
command: command, workingDirectory: args.outputDirectory);
373352

374353
if (results.exitCode != 0) {
375354
return Future.error(
@@ -415,18 +394,8 @@ class OpenapiGenerator extends GeneratorForAnnotation<annots.Openapi> {
415394
),
416395
);
417396

418-
ProcessResult results;
419-
if (!testMode) {
420-
results = await Process.run(
421-
command.executable,
422-
command.arguments,
423-
runInShell: Platform.isWindows,
424-
workingDirectory: args.outputDirectory,
425-
);
426-
} else {
427-
results = ProcessResult(999999, 0, null, null);
428-
}
429-
397+
final results = await runExternalProcess(
398+
command: command, workingDirectory: args.outputDirectory);
430399
if (results.exitCode != 0) {
431400
return Future.error(
432401
OutputMessage(
@@ -499,17 +468,8 @@ class OpenapiGenerator extends GeneratorForAnnotation<annots.Openapi> {
499468
/// Format the generated code in the output directory.
500469
Future<void> formatCode({required GeneratorArguments args}) async {
501470
final command = Command(executable: 'dart', arguments: ['format', './']);
502-
ProcessResult result;
503-
if (!testMode) {
504-
result = await Process.run(
505-
command.executable,
506-
command.arguments,
507-
workingDirectory: args.outputDirectory,
508-
runInShell: Platform.isWindows,
509-
);
510-
} else {
511-
result = ProcessResult(99999, 0, null, null);
512-
}
471+
final result = await runExternalProcess(
472+
command: command, workingDirectory: args.outputDirectory);
513473

514474
if (result.exitCode != 0) {
515475
return Future.error(
@@ -522,9 +482,20 @@ class OpenapiGenerator extends GeneratorForAnnotation<annots.Openapi> {
522482
);
523483
} else {
524484
logOutputMessage(
525-
log: log,
526-
communication:
527-
OutputMessage(message: 'Successfully formatted code.'));
485+
log: log,
486+
communication: OutputMessage(
487+
message: 'Successfully formatted code.',
488+
),
489+
);
528490
}
529491
}
492+
493+
Future<ProcessResult> runExternalProcess(
494+
{required Command command, required String workingDirectory}) =>
495+
Process.run(
496+
command.executable,
497+
command.arguments,
498+
workingDirectory: workingDirectory,
499+
runInShell: Platform.isWindows,
500+
);
530501
}

openapi-generator/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@ dev_dependencies:
2424
source_gen_test:
2525
pedantic:
2626
coverage: ^1.6.3
27+
mockito:
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import 'dart:io';
2+
3+
import 'package:analyzer/dart/analysis/session.dart';
4+
import 'package:analyzer/dart/element/element.dart';
5+
import 'package:analyzer/dart/element/type.dart';
6+
import 'package:analyzer/src/generated/engine.dart';
7+
import 'package:analyzer/src/generated/source.dart';
8+
import 'package:build_test/build_test.dart';
9+
import 'package:logging/logging.dart';
10+
import 'package:mockito/mockito.dart';
11+
import 'package:openapi_generator/src/models/generator_arguments.dart';
12+
import 'package:openapi_generator/src/models/output_message.dart';
13+
import 'package:openapi_generator/src/openapi_generator_runner.dart';
14+
import 'package:pub_semver/src/version.dart';
15+
import 'package:source_gen/source_gen.dart';
16+
import 'package:test/test.dart';
17+
18+
import 'mocks.mocks.dart';
19+
import 'utils.dart';
20+
21+
void main() {
22+
group('OpenApiGenerator', () {
23+
group('NextGen', () {
24+
late MockConstantReader mockedAnnotations;
25+
late ConstantReader defaultAnnotations;
26+
late MockOpenapiGenerator generator;
27+
late GeneratorArguments realArguments;
28+
setUpAll(() async {
29+
mockedAnnotations = MockConstantReader();
30+
defaultAnnotations = (await resolveSource(
31+
File('$testSpecPath/next_gen_builder_test_config.dart')
32+
.readAsStringSync(),
33+
(resolver) async =>
34+
(await resolver.findLibraryByName('test_lib'))!))
35+
.getClass('TestClassConfig')!
36+
.metadata
37+
.map((e) => ConstantReader(e.computeConstantValue()!))
38+
.first;
39+
realArguments = GeneratorArguments(annotations: defaultAnnotations);
40+
generator = MockOpenapiGenerator();
41+
});
42+
43+
test('throws InvalidGenerationSourceError when not a class', () async {
44+
try {
45+
await OpenapiGenerator().generateForAnnotatedElement(
46+
MockMethodElement(), defaultAnnotations, MockBuildStep());
47+
fail('Should throw when not ClassElement');
48+
} catch (e, _) {
49+
expect(e, isA<InvalidGenerationSourceError>());
50+
e as InvalidGenerationSourceError;
51+
expect(e.message, 'Generator cannot target ``.');
52+
expect(e.todo, 'Remove the [Openapi] annotation from ``.');
53+
}
54+
});
55+
56+
test('throws AssertionError when useCache is set but useNextGen is not',
57+
() async {
58+
final mockedUseNextGen = MockConstantReader();
59+
when(mockedUseNextGen.literalValue).thenReturn(false);
60+
61+
final mockedUseCachePath = MockConstantReader();
62+
when(mockedUseCachePath.literalValue).thenReturn('something');
63+
64+
when(mockedAnnotations.read('useNextGen')).thenReturn(mockedUseNextGen);
65+
when(mockedAnnotations.read('cachePath'))
66+
.thenReturn(mockedUseCachePath);
67+
68+
try {
69+
await OpenapiGenerator().generateForAnnotatedElement(
70+
MockClassElement(), mockedAnnotations, MockBuildStep());
71+
fail('Should throw when useNextGen is false and cache path is set.');
72+
} catch (e, _) {
73+
expect(e, isA<AssertionError>());
74+
e as AssertionError;
75+
expect(e.message, 'useNextGen must be set when using cachePath');
76+
}
77+
});
78+
79+
group('runOpenApiJar', () {
80+
test('returns an error when the jar command fails', () async {
81+
when(
82+
generator.runExternalProcess(
83+
command: anyNamed('command'),
84+
workingDirectory: anyNamed(
85+
'workingDirectory',
86+
),
87+
),
88+
).thenAnswer(
89+
(realInvocation) => Future.value(
90+
ProcessResult(999, 1, '', 'something went wrong'),
91+
),
92+
);
93+
94+
try {
95+
await generator.runOpenApiJar(arguments: realArguments);
96+
fail(
97+
'should have returned an error log.',
98+
);
99+
} catch (e, _) {
100+
expect(e, isA<OutputMessage>());
101+
e as OutputMessage;
102+
expect(e.level, Level.SEVERE);
103+
expect(e.message, 'Codegen Failed. Generator output:');
104+
expect(e.additionalContext, 'something went wrong');
105+
expect(e.stackTrace, isNotNull);
106+
}
107+
});
108+
});
109+
});
110+
});
111+
}

openapi-generator/test/mocks.dart

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import 'dart:io';
2+
3+
import 'package:analyzer/dart/element/element.dart';
4+
import 'package:build/build.dart';
5+
import 'package:mockito/annotations.dart';
6+
import 'package:openapi_generator/src/openapi_generator_runner.dart';
7+
import 'package:source_gen/source_gen.dart';
8+
9+
@GenerateNiceMocks([
10+
MockSpec<OpenapiGenerator>(),
11+
MockSpec<ConstantReader>(),
12+
MockSpec<BuildStep>(),
13+
MockSpec<MethodElement>(),
14+
MockSpec<ClassElement>(),
15+
MockSpec<Process>(),
16+
])
17+
void main() {}

0 commit comments

Comments
 (0)