-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AF-1917: Make over_react_codemod script idempotent #5
Changes from 1 commit
02fa070
c879539
21c3f07
454fe99
3e96b96
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,7 +32,7 @@ def get_factory_name(line): | |
>>> get_factory_name('UiFactory<DemoProps> Demo;') | ||
'Demo' | ||
""" | ||
match = re.search(r' (\w+);', line) | ||
match = re.search(r'(\w+);', line) | ||
if not match: | ||
raise Exception('Could not parse factory name from:\n%s' % line) | ||
return match.group(1) | ||
|
@@ -140,9 +140,13 @@ def factories_suggest(lines, path): | |
|
||
for line_number, line in enumerate(lines): | ||
if line.startswith('UiFactory'): | ||
factory_name = get_factory_name(line) | ||
|
||
if '$' + factory_name in line: | ||
continue | ||
|
||
need_part = True | ||
|
||
factory_name = get_factory_name(line) | ||
ignore_line = '// ignore: undefined_identifier\n' | ||
new_line = line.replace(';\n', ' = $%s;\n' % (factory_name)) | ||
|
||
|
@@ -219,6 +223,10 @@ def props_metas_suggest(lines, path): | |
found_class_opening = False | ||
class_body_is_empty = False | ||
props_class_name = None | ||
ignore_line = ' // ignore: undefined_identifier, undefined_class, const_initialized_with_non_constant_value\n' | ||
|
||
if ignore_line in lines: | ||
continue | ||
|
||
for o, line_b in enumerate(lines[line_number:]): | ||
if line_b.startswith('class ') or line_b.startswith('abstract class '): | ||
|
@@ -240,9 +248,8 @@ def props_metas_suggest(lines, path): | |
|
||
last_class_def_line = lines[line_number + offset] | ||
if class_body_is_empty: | ||
last_class_def_line = last_class_def_line.replace('{}\n', '{\n') | ||
last_class_def_line = last_class_def_line.replace('{}\n', '{\n') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. one too many indents here |
||
|
||
ignore_line = ' // ignore: undefined_identifier, undefined_class, const_initialized_with_non_constant_value\n' | ||
meta_line = ' static const PropsMeta meta = $metaFor%s;\n' % props_class_name | ||
# debug_line = 'line endings: %s' % line_endings | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,68 +11,112 @@ void main() { | |
final pathToExpectedResults = p.absolute('test/test_fixtures/after_codemod/component_in_parts/component_in_part.dart'); | ||
final pathToTestFile = p.absolute('test/test_fixtures/before_codemod/component_in_parts/temp/component_in_part.dart'); | ||
|
||
makeComparison(pathToTestFixtureDirectory, pathToExpectedResults, pathToTestFile); | ||
setupAndMakeComparison(pathToTestFixtureDirectory, pathToExpectedResults, pathToTestFile); | ||
}); | ||
|
||
test('correctly converts components in a library', () async { | ||
final pathToTestFixtureDirectory = p.absolute('test/test_fixtures/before_codemod/component_in_library'); | ||
final pathToExpectedResults = p.absolute('test/test_fixtures/after_codemod/component_in_library/component_in_library.dart'); | ||
final pathToTestFile = p.absolute('test/test_fixtures/before_codemod/component_in_library/temp/component_in_library.dart'); | ||
|
||
makeComparison(pathToTestFixtureDirectory, pathToExpectedResults, pathToTestFile); | ||
setupAndMakeComparison(pathToTestFixtureDirectory, pathToExpectedResults, pathToTestFile); | ||
}); | ||
|
||
test('correctly converts components without props', () async { | ||
final pathToTestFixtureDirectory = p.absolute('test/test_fixtures/before_codemod/component_without_props'); | ||
final pathToExpectedResults = p.absolute('test/test_fixtures/after_codemod/component_without_props/component_without_props.dart'); | ||
final pathToTestFile = p.absolute('test/test_fixtures/before_codemod/component_without_props/temp/component_without_props.dart'); | ||
|
||
makeComparison(pathToTestFixtureDirectory, pathToExpectedResults, pathToTestFile); | ||
setupAndMakeComparison(pathToTestFixtureDirectory, pathToExpectedResults, pathToTestFile); | ||
}); | ||
|
||
test('correctly converts single \$PropKeys reference', () async { | ||
final pathToTestFixtureDirectory = p.absolute('test/test_fixtures/before_codemod/mock_test_single_prop'); | ||
final pathToExpectedResults = p.absolute('test/test_fixtures/after_codemod/mock_test_single_prop/mock_test_single_prop.dart'); | ||
final pathToTestFile = p.absolute('test/test_fixtures/before_codemod/mock_test_single_prop/temp/mock_test_single_prop.dart'); | ||
|
||
await makeComparison(pathToTestFixtureDirectory, pathToExpectedResults, pathToTestFile); | ||
await setupAndMakeComparison(pathToTestFixtureDirectory, pathToExpectedResults, pathToTestFile); | ||
}); | ||
|
||
test('correctly coverts multiple \$PropKeys references', () async { | ||
test('correctly converts multiple \$PropKeys references', () async { | ||
final pathToTestFixtureDirectory = p.absolute('test/test_fixtures/before_codemod/mock_test_multiple_props'); | ||
final pathToExpectedResults = p.absolute('test/test_fixtures/after_codemod/mock_test_multiple_props/mock_test_multiple_props.dart'); | ||
final pathToTestFile = p.absolute('test/test_fixtures/before_codemod/mock_test_multiple_props/temp/mock_test_multiple_props.dart'); | ||
|
||
await makeComparison(pathToTestFixtureDirectory, pathToExpectedResults, pathToTestFile); | ||
await setupAndMakeComparison(pathToTestFixtureDirectory, pathToExpectedResults, pathToTestFile); | ||
}); | ||
|
||
test('correctly coverts single \$Prop reference', () async { | ||
test('correctly converts single \$Prop reference', () async { | ||
final pathToTestFixtureDirectory = p.absolute('test/test_fixtures/before_codemod/component_with_single_consumed_prop'); | ||
final pathToExpectedResults = p.absolute('test/test_fixtures/after_codemod/component_with_single_consumed_prop/component_with_single_consumed_prop.dart'); | ||
final pathToTestFile = p.absolute('test/test_fixtures/before_codemod/component_with_single_consumed_prop/temp/component_with_single_consumed_prop.dart'); | ||
|
||
await makeComparison(pathToTestFixtureDirectory, pathToExpectedResults, pathToTestFile); | ||
await setupAndMakeComparison(pathToTestFixtureDirectory, pathToExpectedResults, pathToTestFile); | ||
}); | ||
|
||
test('correctly coverts multiple \$Prop references', () async { | ||
test('correctly converts multiple \$Prop references', () async { | ||
final pathToTestFixtureDirectory = p.absolute('test/test_fixtures/before_codemod/component_with_multiple_consumed_props'); | ||
final pathToExpectedResults = p.absolute('test/test_fixtures/after_codemod/component_with_multiple_consumed_props/component_with_multiple_consumed_props.dart'); | ||
final pathToTestFile = p.absolute('test/test_fixtures/before_codemod/component_with_multiple_consumed_props/temp/component_with_multiple_consumed_props.dart'); | ||
|
||
await makeComparison(pathToTestFixtureDirectory, pathToExpectedResults, pathToTestFile); | ||
await setupAndMakeComparison(pathToTestFixtureDirectory, pathToExpectedResults, pathToTestFile); | ||
}); | ||
|
||
test('script is idempotent when modifiying a component', () async { | ||
final pathToTestFixtureDirectory = p.absolute('test/test_fixtures/before_codemod/component_with_multiple_consumed_props'); | ||
final pathToExpectedResults = p.absolute('test/test_fixtures/after_codemod/component_with_multiple_consumed_props/component_with_multiple_consumed_props.dart'); | ||
final pathToTestFile = p.absolute('test/test_fixtures/before_codemod/component_with_multiple_consumed_props/temp/component_with_multiple_consumed_props.dart'); | ||
final pathToTempDirectory = p.absolute('${pathToTestFixtureDirectory}/temp'); | ||
final pathToMigrater = p.absolute('migrater.py'); | ||
|
||
await setupTempDirectory(pathToTempDirectory, pathToTestFixtureDirectory); | ||
|
||
/// Codemod the temporary directory contents twice. | ||
await codemodTempDirectory(pathToMigrater, pathToTempDirectory); | ||
await codemodTempDirectory(pathToMigrater, pathToTempDirectory); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a lot of extra setup for each of these idempotent tests. Instead, I think we could accomplish this via an optional boolean param on the |
||
|
||
/// Compare expected results against codemod file in temp directory. | ||
String expectedResults = new File(pathToExpectedResults).readAsStringSync(); | ||
String testFile = new File(pathToTestFile).readAsStringSync(); | ||
|
||
expect(testFile, equals(expectedResults)); | ||
|
||
await removeTempDirectory(pathToTestFixtureDirectory); | ||
}); | ||
|
||
test('script is idempotent when modifiying a test', () async { | ||
final pathToTestFixtureDirectory = p.absolute('test/test_fixtures/before_codemod/mock_test_multiple_props'); | ||
final pathToExpectedResults = p.absolute('test/test_fixtures/after_codemod/mock_test_multiple_props/mock_test_multiple_props.dart'); | ||
final pathToTestFile = p.absolute('test/test_fixtures/before_codemod/mock_test_multiple_props/temp/mock_test_multiple_props.dart'); | ||
final pathToTempDirectory = p.absolute('${pathToTestFixtureDirectory}/temp'); | ||
final pathToMigrater = p.absolute('migrater.py'); | ||
|
||
await setupTempDirectory(pathToTempDirectory, pathToTestFixtureDirectory); | ||
|
||
/// Code mode the temporary directory contents twice. | ||
await codemodTempDirectory(pathToMigrater, pathToTempDirectory); | ||
await codemodTempDirectory(pathToMigrater, pathToTempDirectory); | ||
|
||
/// Compare expected results against codemod file in temp directory. | ||
String expectedResults = new File(pathToExpectedResults).readAsStringSync(); | ||
String testFile = new File(pathToTestFile).readAsStringSync(); | ||
|
||
expect(testFile, equals(expectedResults)); | ||
|
||
await removeTempDirectory(pathToTestFixtureDirectory); | ||
}); | ||
}); | ||
} | ||
|
||
/// Creates a temp directory and copies the un-modified test fixtures to it. Then | ||
/// migrater.py is run on these test fixtures to make the codemod changes. | ||
Future<Null> setupAndCodemod(String pathToTestFixtureDirectory) async { | ||
final pathToMigrater = p.absolute('migrater.py'); | ||
final pathToTempDirectory = p.absolute('${pathToTestFixtureDirectory}/temp'); | ||
|
||
/// Create a temporary directory and copy files from the specified before_codmod | ||
/// test fixture directory. | ||
Future<Null> setupTempDirectory(String pathToTempDirectory, String pathToTestFixtureDirectory) async { | ||
await Process.run('/bin/bash', | ||
['-c', 'mkdir -p temp && cp -r *.dart /$pathToTempDirectory'], workingDirectory: pathToTestFixtureDirectory); | ||
} | ||
|
||
/// Runs the migrater.py script to codemod files in the temporary directory. | ||
Future<Null> codemodTempDirectory(String pathToMigrater, String pathToTempDirectory) async { | ||
await Process.start('/bin/bash', ['-c', 'python $pathToMigrater'], workingDirectory: pathToTempDirectory).then((Process process) async { | ||
await process.stdin.write('A\nA\n'); | ||
await process.stdin.close(); | ||
|
@@ -81,20 +125,25 @@ Future<Null> setupAndCodemod(String pathToTestFixtureDirectory) async { | |
} | ||
|
||
/// Deletes the temp directory. | ||
Future<Null> removeTempDir(String pathToTestFixtureDirectory) async { | ||
Future<Null> removeTempDirectory(String pathToTestFixtureDirectory) async { | ||
await Process.run('/bin/bash', ['-c', 'rm -R temp'], workingDirectory: pathToTestFixtureDirectory); | ||
} | ||
|
||
/// Makes the comparison between the expected result (migrated file) and the test file | ||
/// (the file that is migrated during the test run in a temp directory). | ||
Future<Null> makeComparison(String pathToTestFixtureDirectory, String pathToExpectedResults, String pathToTestFile) async { | ||
await setupAndCodemod(pathToTestFixtureDirectory); | ||
/// Setup and codemods the temporary directory and then makes the comparison | ||
/// between the expected result (migrated file) and the test file | ||
/// (the file that is migrated during setup). | ||
Future<Null> setupAndMakeComparison(String pathToTestFixtureDirectory, String pathToExpectedResults, String pathToTestFile) async { | ||
final pathToMigrater = p.absolute('migrater.py'); | ||
final pathToTempDirectory = p.absolute('${pathToTestFixtureDirectory}/temp'); | ||
|
||
await setupTempDirectory(pathToTempDirectory, pathToTestFixtureDirectory); | ||
await codemodTempDirectory(pathToMigrater, pathToTempDirectory); | ||
|
||
/// Compare expected results against codemod file in temp directory. | ||
String expectedResults = new File(pathToExpectedResults).readAsStringSync(); | ||
String testFile = new File(pathToTestFile).readAsStringSync(); | ||
|
||
expect(testFile, equals(expectedResults)); | ||
|
||
await removeTempDir(pathToTestFixtureDirectory); | ||
await removeTempDirectory(pathToTestFixtureDirectory); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prior to this boilerplate change, factory definitions would always be on one line. But with this change, dartfmt may break the right-hand-side of the factory assignment onto its own line like so:
We'll need to account for this; currently the script throws when it encounters this.
I think we should add a new method that determines whether or not the current line needs a factory update (which also accounts for lines that have already been transformed). Something like this: