1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-10-31 21:52:59 +00:00

Merge branch 'master' into mc-1.14.x

This commit is contained in:
SquidDev
2020-05-13 14:04:28 +01:00
69 changed files with 1195 additions and 141 deletions

View File

@@ -30,12 +30,14 @@ import org.opentest4j.AssertionFailedError;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
@@ -58,6 +60,8 @@ import static dan200.computercraft.api.lua.ArgumentHelper.getType;
*/
public class ComputerTestDelegate
{
private static final File REPORT_PATH = new File( "test-files/luacov.report.out" );
private static final Logger LOG = LogManager.getLogger( ComputerTestDelegate.class );
private static final long TICK_TIME = TimeUnit.MILLISECONDS.toNanos( 50 );
@@ -77,12 +81,15 @@ public class ComputerTestDelegate
private final Condition hasFinished = lock.newCondition();
private boolean finished = false;
private Map<String, Map<Double, Double>> finishedWith;
@BeforeEach
public void before() throws IOException
{
ComputerCraft.logPeripheralErrors = true;
if( REPORT_PATH.delete() ) ComputerCraft.log.info( "Deleted previous coverage report." );
Terminal term = new Terminal( 78, 20 );
IWritableMount mount = new FileMount( new File( "test-files/mount" ), 10_000_000 );
@@ -264,6 +271,13 @@ public class ComputerTestDelegate
try
{
finished = true;
if( arguments.length > 0 )
{
@SuppressWarnings( "unchecked" )
Map<String, Map<Double, Double>> finished = (Map<String, Map<Double, Double>>) arguments[0];
finishedWith = finished;
}
hasFinished.signal();
}
finally
@@ -281,7 +295,7 @@ public class ComputerTestDelegate
}
@AfterEach
public void after() throws InterruptedException
public void after() throws InterruptedException, IOException
{
try
{
@@ -316,6 +330,14 @@ public class ComputerTestDelegate
// And shutdown
computer.shutdown();
}
if( finishedWith != null )
{
try( BufferedWriter writer = Files.newBufferedWriter( REPORT_PATH.toPath() ) )
{
new LuaCoverage( finishedWith ).write( writer );
}
}
}
@TestFactory

View File

@@ -0,0 +1,158 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.core;
import com.google.common.base.Strings;
import dan200.computercraft.ComputerCraft;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import org.squiddev.cobalt.Prototype;
import org.squiddev.cobalt.compiler.CompileException;
import org.squiddev.cobalt.compiler.LuaC;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
class LuaCoverage
{
private static final Path ROOT = new File( "src/main/resources/assets/computercraft/lua" ).toPath();
private static final Path BIOS = ROOT.resolve( "bios.lua" );
private static final Path APIS = ROOT.resolve( "rom/apis" );
private static final Path SHELL = ROOT.resolve( "rom/programs/shell.lua" );
private static final Path MULTISHELL = ROOT.resolve( "rom/programs/advanced/multishell.lua" );
private static final Path TREASURE = ROOT.resolve( "treasure" );
private final Map<String, Map<Double, Double>> coverage;
private final String blank;
private final String zero;
private final String countFormat;
LuaCoverage( Map<String, Map<Double, Double>> coverage )
{
this.coverage = coverage;
int max = (int) coverage.values().stream()
.flatMapToDouble( x -> x.values().stream().mapToDouble( y -> y ) )
.max().orElse( 0 );
int maxLen = Math.max( 1, (int) Math.ceil( Math.log10( max ) ) );
blank = Strings.repeat( " ", maxLen + 1 );
zero = Strings.repeat( "*", maxLen ) + "0";
countFormat = "%" + (maxLen + 1) + "d";
}
void write( Writer out ) throws IOException
{
Files.find( ROOT, Integer.MAX_VALUE, ( path, attr ) -> attr.isRegularFile() && !path.startsWith( TREASURE ) ).forEach( path -> {
Path relative = ROOT.relativize( path );
String full = relative.toString().replace( '\\', '/' );
if( !full.endsWith( ".lua" ) ) return;
Map<Double, Double> files = Stream.of(
coverage.remove( "/" + full ),
path.equals( BIOS ) ? coverage.remove( "bios.lua" ) : null,
path.equals( SHELL ) ? coverage.remove( "shell.lua" ) : null,
path.equals( MULTISHELL ) ? coverage.remove( "multishell.lua" ) : null,
path.startsWith( APIS ) ? coverage.remove( path.getFileName().toString() ) : null
)
.filter( Objects::nonNull )
.flatMap( x -> x.entrySet().stream() )
.collect( Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, Double::sum ) );
try
{
writeCoverageFor( out, path, files );
}
catch( IOException e )
{
throw new UncheckedIOException( e );
}
} );
for( String filename : coverage.keySet() )
{
if( filename.startsWith( "/test-rom/" ) ) continue;
ComputerCraft.log.warn( "Unknown file {}", filename );
}
}
private void writeCoverageFor( Writer out, Path fullName, Map<Double, Double> visitedLines ) throws IOException
{
if( !Files.exists( fullName ) )
{
ComputerCraft.log.error( "Cannot locate file {}", fullName );
return;
}
IntSet activeLines = getActiveLines( fullName.toFile() );
out.write( "==============================================================================\n" );
out.write( fullName.toString().replace( '\\', '/' ) );
out.write( "\n" );
out.write( "==============================================================================\n" );
try( BufferedReader reader = Files.newBufferedReader( fullName ) )
{
String line;
int lineNo = 0;
while( (line = reader.readLine()) != null )
{
lineNo++;
Double count = visitedLines.get( (double) lineNo );
if( count != null )
{
out.write( String.format( countFormat, count.intValue() ) );
}
else if( activeLines.contains( lineNo ) )
{
out.write( zero );
}
else
{
out.write( blank );
}
out.write( ' ' );
out.write( line );
out.write( "\n" );
}
}
}
private static IntSet getActiveLines( File file ) throws IOException
{
IntSet activeLines = new IntOpenHashSet();
try( InputStream stream = new FileInputStream( file ) )
{
Prototype proto = LuaC.compile( stream, "@" + file.getPath() );
Queue<Prototype> queue = new ArrayDeque<>();
queue.add( proto );
while( (proto = queue.poll()) != null )
{
int[] lines = proto.lineinfo;
if( lines != null )
{
for( int line : lines )
{
activeLines.add( line );
}
}
if( proto.p != null ) Collections.addAll( queue, proto.p );
}
}
catch( CompileException e )
{
throw new IllegalStateException( "Cannot compile", e );
}
return activeLines;
}
}