@Test
  public void testTypeCheckingRobustQueryLogFixed() throws IOException, ParseException {
    final String source =
        "proto \"querylog.proto\"\n	static MINUTE: float = 0.0; static RESOLUTION: int = 5;  # minutes; must be divisor of 60\n	log_record: QueryLogProto = input;\n	queries_per_degree: table sum[t: time][lat: int][lon: int] of int;\n	loc: Location = locationinfo(log_record.ip);\n	if (def(loc)) {\n	    t: time = log_record.time_usec;\n	    m: int = minuteof(t); # within the hour\n	    m = m - m % RESOLUTION;\n	    t = trunctohour(t) + time(m * int(MINUTE));\n	    emit queries_per_degree[t][int(loc.lat)][int(loc.lon)] <- 1;\n	}";

    final SymbolTable st = new SymbolTable(new SizzleBytes());

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);

    Assert.assertEquals(
        "queries_per_degree is not an unweighted table of ints indexed by various",
        new SizzleTable(
            new SizzleInt(),
            Arrays.asList(new SizzleTime(), new SizzleInt(), new SizzleInt()),
            null),
        st.get("queries_per_degree"));

    // assertEquals("t is not an time", new SizzleTime(), st.get("t"));
    // assertEquals("m is not an int", new SizzleInt(), st.get("m"));
    Assert.assertEquals("RESOLUTION is not an int", new SizzleInt(), st.get("RESOLUTION"));

    final List<SizzleType> lmembers =
        new ArrayList<SizzleType>(Arrays.asList(new SizzleFloat(), new SizzleFloat()));

    Assert.assertEquals("loc is not a Location", new SizzleTuple(lmembers), st.get("loc"));

    final List<SizzleType> qlpmembers =
        new ArrayList<SizzleType>(Arrays.asList(new SizzleString(), new SizzleInt()));

    Assert.assertEquals(
        "log_record is not a QueryLogProto", new SizzleTuple(qlpmembers), st.get("log_record"));
  }
  @Test
  public void testTypeCheckingVisitorTypeDeclaration() throws IOException, ParseException {
    final String source =
        "type my_bool = bool;\ntype Coordinates = { x: float, y: float };\ntype CityMap = map [city_name: string] of Coordinates;\n";

    final SymbolTable st = new SymbolTable();

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);

    Assert.assertEquals(
        "my_bool is not an alias for bool",
        new SizzleName(new SizzleBool()),
        st.getType("my_bool"));
    final ArrayList<SizzleType> members =
        new ArrayList<SizzleType>(Arrays.asList(new SizzleFloat(), new SizzleFloat()));
    Assert.assertEquals(
        "Coordinates is not is not an alias for a tuple of x: float, y: float",
        new SizzleName(new SizzleTuple(members)),
        st.getType("Coordinates"));
    Assert.assertEquals(
        "CityMap is not an alias for a mapping from string to tuple of x: float, y: float",
        new SizzleName(new SizzleMap(new SizzleString(), new SizzleName(new SizzleTuple(members)))),
        st.getType("CityMap"));
  }
  @Test(expected = TypeException.class)
  public void testTypeCheckingVisitorWordCountMissingEmitIndex()
      throws IOException, ParseException {
    final String source =
        "out: table sum[key: string][month: int][day: int] of int;\nstatic keywords: array of string = { \"hitchhiker\", \"benedict\", \"vytorin\", \"itanium\", \"aardvark\" };\nquerywords: array of string = words_from_query();\nmonth: int = month_of_query();\nday: int = day_of_query();\nwhen (i: each int; j: some int; querywords[i] == keywords[j])\n    emit out <- 1;\n";

    final SymbolTable st = new SymbolTable();

    // fake functions for this unit test
    st.setFunction(
        "day_of_query",
        new SizzleFunction(new SizzleInt(), new SizzleType[] {}, "Nonexistant.day_of_query()"));
    st.setFunction(
        "month_of_query",
        new SizzleFunction(new SizzleInt(), new SizzleType[] {}, "Nonexistant.month_of_query()"));
    st.setFunction(
        "words_from_query",
        new SizzleFunction(
            new SizzleArray(new SizzleString()),
            new SizzleType[] {},
            "Nonexistant.words_from_query()"));

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);
  }
  @Test
  public void testTypeCheckingVisitorQueryLog() throws IOException, ParseException {
    final String source =
        "proto \"querylog.proto\"\n\nqueries_per_degree: table sum[lat: int][lon: int] of int;\n\nlog_record: QueryLogProto = input;\nloc: Location = locationinfo(log_record.ip);\nemit queries_per_degree[int(loc.lat)][int(loc.lon)] <- 1;\n";

    final SymbolTable st = new SymbolTable(new SizzleBytes());

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);

    Assert.assertEquals(
        "queries_per_degree is not an unweighted table of ints indexed by ints",
        new SizzleTable(
            new SizzleInt(),
            Arrays.asList(new SizzleScalar[] {new SizzleInt(), new SizzleInt()}),
            null),
        st.get("queries_per_degree"));

    final List<SizzleType> lmembers =
        new ArrayList<SizzleType>(Arrays.asList(new SizzleFloat(), new SizzleFloat()));

    Assert.assertEquals("loc is not a Location", new SizzleTuple(lmembers), st.get("loc"));

    final List<SizzleType> qlpmembers =
        new ArrayList<SizzleType>(Arrays.asList(new SizzleString(), new SizzleInt()));

    Assert.assertEquals(
        "log_record is not a QueryLogProto", new SizzleTuple(qlpmembers), st.get("log_record"));
  }
  @Test(expected = TypeException.class)
  public void testTypeCheckingVisitorCompoundSwitched() throws IOException, ParseException {
    final String source =
        "out: table sum of { count: int, value: float };\nline: string = input;\ntuple: array of string = split(line, \"\\t\");\nemit out <- { float(tuple[8]), 1 };\n";

    final SymbolTable st = new SymbolTable();

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);
  }
  @Test(expected = TypeException.class)
  public void testTypeCheckingVisitorMaxPagerankMissingProto() throws IOException, ParseException {
    final String source =
        "proto \"document.proto\"\nmax_pagerank_url:\n     table maximum(1) [domain: string] of url: string\n           weight pagerank: int;\ndoc: Document = input;\nemit max_pagerank_url[domain(doc.url)] <- doc.url\n     weight doc.pagerank;\n";

    final SymbolTable st = new SymbolTable();

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);
  }
  @Test(expected = TypeException.class)
  public void testTypeCheckingVisitorCompoundBadType() throws IOException, ParseException {
    final String source =
        "s: table sum of { count: int, total: float, sum_of_squares: string };\nx: float = input;\nemit s <- { 1, x, \"x\" };";

    final SymbolTable st = new SymbolTable();

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);
  }
  @Test(expected = TypeException.class)
  public void testTypeCheckingVisitorTypeDeclaredAsVariable() throws IOException, ParseException {
    final String source =
        "times: table collection[timezone: string] of time: string;\ntime: string = input;\nemit times[\"PST8PDT\"] <- string(trunctoday(time(time)));emit times[\"America/New_York\"] <- string(trunctoday(time(time), \"America/New_York\"));\n";

    final SymbolTable st = new SymbolTable();

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);
  }
  @Test(expected = TypeException.class)
  public void testTypeCheckingVisitorUnexpectedWeightInEmit() throws IOException, ParseException {
    final String source =
        "allez: table collection of entry: string;\nline: string = input;\nemit allez <- line weight 1.2;\n";

    final SymbolTable st = new SymbolTable();

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);
  }
  @Test(expected = TypeException.class)
  public void testTypeCheckingVisitorMissingWeightInEmit() throws IOException, ParseException {
    final String source =
        "logger: table log of entry: string weight level: int;\nline: string = input;\nemit logger <- line;\n";

    final SymbolTable st = new SymbolTable();

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);
  }
  @Test(expected = TypeException.class)
  public void testTypeCheckingRobustQueryLogBad() throws IOException, ParseException {
    // this is an example from the Sawzall paper, doesn't define MINUTE
    final String source =
        "proto \"querylog.proto\"\n	static RESOLUTION: int = 5;  # minutes; must be divisor of 60\n	log_record: QueryLogProto = input;\n	queries_per_degree: table sum[t: time][lat: int][lon: int] of int;\n	loc: Location = locationinfo(log_record.ip);\n	if (def(loc)) {\n	    t: time = log_record.time_usec;\n	    m: int = minuteof(t); # within the hour\n	    m = m - m % RESOLUTION;\n	    t = trunctohour(t) + time(m * int(MINUTE));\n	    emit queries_per_degree[t][int(loc.lat)][int(loc.lon)] <- 1;\n	}";

    final SymbolTable st = new SymbolTable();

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);
  }
  @Test(expected = TypeException.class)
  public void testTypeCheckingVisitorWordCountMissingFunctions()
      throws IOException, ParseException {
    final String source =
        "out: table sum[key: string][month: int][day: int] of int;\nstatic keywords: array of string = { \"hitchhiker\", \"benedict\", \"vytorin\", \"itanium\", \"aardvark\" };\nquerywords: array of string = words_from_query();\nmonth: int = month_of_query();\nday: int = day_of_query();\nwhen (i: each int; j: some int; querywords[i] == keywords[j])\n    emit out[keywords[j]][month][day] <- 1;\n";

    final SymbolTable st = new SymbolTable();

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);
  }
  @Test(expected = TypeException.class)
  public void testTypeCheckingVisitorRealWordCountUnsupportedParameter()
      throws IOException, ParseException {
    // sum doesn't take a parameter
    final String source =
        "out: table sum(10) of { count: int, value: float };\nline: string = input;\ntuple: array of string = sawzall(line, \"[^\\t]+\");\nemit out <- { 1, float(tuple[8]) };\n";

    final SymbolTable st = new SymbolTable();

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);
  }
  @Test
  public void testTypeCheckingVisitorWordCount() throws IOException, ParseException {
    final String source =
        "out: table sum[key: string][month: int][day: int] of int;\nstatic keywords: array of string = { \"hitchhiker\", \"benedict\", \"vytorin\", \"itanium\", \"aardvark\" };\nquerywords: array of string = words_from_query();\nmonth: int = month_of_query();\nday: int = day_of_query();\nwhen (i: each int; j: some int; querywords[i] == keywords[j])\n    emit out[keywords[j]][month][day] <- 1;\n";

    final SymbolTable st = new SymbolTable();

    // fake functions for this unit test
    st.setFunction(
        "day_of_query",
        new SizzleFunction(new SizzleInt(), new SizzleType[] {}, "Nonexistant.day_of_query()"));
    st.setFunction(
        "month_of_query",
        new SizzleFunction(new SizzleInt(), new SizzleType[] {}, "Nonexistant.month_of_query()"));
    st.setFunction(
        "words_from_query",
        new SizzleFunction(
            new SizzleArray(new SizzleString()),
            new SizzleType[] {},
            "Nonexistant.words_from_query()"));

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);

    Assert.assertEquals(
        "out is not an unweighted table of ints indexed by various",
        new SizzleTable(
            new SizzleInt(),
            Arrays.asList(new SizzleString(), new SizzleInt(), new SizzleInt()),
            null),
        st.get("out"));

    Assert.assertEquals(
        "keywords is not an array of strings",
        new SizzleArray(new SizzleString()),
        st.get("keywords"));
    Assert.assertEquals(
        "querywords is not an array of strings",
        new SizzleArray(new SizzleString()),
        st.get("querywords"));

    Assert.assertEquals("month is not an int", new SizzleInt(), st.get("month"));
    Assert.assertEquals("day is not an int", new SizzleInt(), st.get("day"));
  }
  @Test
  public void testTypeCheckingVisitorP4Stat() throws IOException, ParseException {
    final String source =
        "proto \"p4stat.proto\"\nsubmitsthroughweek: table sum[minute: int] of count: int;\nlog: P4ChangelistStats = input;\nt: time = log.time; # microseconds\nminute: int = minuteof(t)+60*(hourof(t)+24*(dayofweek(t)-1));\nemit submitsthroughweek[minute] <- 1;\n";

    final SymbolTable st = new SymbolTable(new SizzleBytes());

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);

    Assert.assertEquals(
        "submitsthroughweek is not an unweighted table of ints indexed by int",
        new SizzleTable(new SizzleInt(), Arrays.asList(new SizzleScalar[] {new SizzleInt()}), null),
        st.get("submitsthroughweek"));
    final List<SizzleType> members = new ArrayList<SizzleType>(Arrays.asList(new SizzleInt()));
    Assert.assertEquals("log is not a P4ChangelistStats", new SizzleTuple(members), st.get("log"));
    Assert.assertEquals("t is not a time", new SizzleTime(), st.get("t"));
    Assert.assertEquals("minute is not an int", new SizzleInt(), st.get("minute"));
  }
  @Test
  public void testTypeCheckingVisitorSimpleCompound() throws IOException, ParseException {
    final String source =
        "s: table sum of { count: int, total: float, sum_of_squares: float };\nx: float = input;\nemit s <- { 1, x, x * x };";

    final SymbolTable st = new SymbolTable();

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);

    final List<SizzleType> members =
        new ArrayList<SizzleType>(
            Arrays.asList(new SizzleInt(), new SizzleFloat(), new SizzleFloat()));

    Assert.assertEquals(
        "s is not an unweighted, unindexed table of tuple of int, float and float",
        new SizzleTable(new SizzleTuple(members)),
        st.get("s"));

    Assert.assertEquals("x is not a float", new SizzleFloat(), st.get("x"));
  }
  @Test
  public void testTypeCheckingVisitorMap() throws IOException, ParseException {
    final String source =
        "xlated: table collection of lang: string;\nstatic CJK: map[string] of string = {\n\t\"zh\": \"Chinese\",\n\t\"ja\": \"Japanese\",\n\"ko\": \"Korean\"\n};\nabbr: string = input;\nemit xlated <- CJK[abbr];\n";

    final SymbolTable st = new SymbolTable();

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);

    Assert.assertEquals(
        "xlated is not an unindexed, unweighted table of string",
        new SizzleTable(new SizzleString(), null),
        st.get("xlated"));

    Assert.assertEquals("abbr is not a string", new SizzleString(), st.get("abbr"));
    Assert.assertEquals(
        "CJK is not a mapping from string to string",
        new SizzleMap(new SizzleString(), new SizzleString()),
        st.get("CJK"));
  }
  @Test
  public void testTypeCheckingVisitorMaxPagerank() throws IOException, ParseException {
    final String source =
        "proto \"sizzle_document.proto\"\nmax_pagerank_url:\n     table maximum(1) [domain: string] of url: string\n           weight pagerank: float;\ndoc: Document = input;\nemit max_pagerank_url[domain(doc.url)] <- doc.url\n     weight doc.pagerank;\n";

    final SymbolTable st = new SymbolTable(new SizzleBytes());

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);

    Assert.assertEquals(
        "max_pagerank_url is not table of strings indexed by string weighted by int",
        new SizzleTable(
            new SizzleString(),
            Arrays.asList(new SizzleScalar[] {new SizzleString()}),
            new SizzleFloat()),
        st.get("max_pagerank_url"));
    final List<SizzleType> members =
        new ArrayList<SizzleType>(Arrays.asList(new SizzleString(), new SizzleInt()));
    Assert.assertEquals("doc is not a Document", new SizzleTuple(members), st.get("doc"));
  }
  @Test
  public void testTypeCheckingVisitorCompoundImplicitCast() throws IOException, ParseException {
    final String source =
        "out: table sum of { count: int, value: float };\nline: string = input;\ntuple: array of string = sawzall(line, \"[^\\t]+\");\nvalue: float = tuple[8];\nemit out <- { 1, value };\n";

    final SymbolTable st = new SymbolTable();

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);

    final List<SizzleType> members =
        new ArrayList<SizzleType>(Arrays.asList(new SizzleInt(), new SizzleFloat()));

    Assert.assertEquals(
        "out is not an unindexed, unweighted table of int and float",
        new SizzleTable(new SizzleTuple(members)),
        st.get("out"));

    Assert.assertEquals("line is not a string", new SizzleString(), st.get("line"));
    Assert.assertEquals(
        "tuple is not an array of strings", new SizzleArray(new SizzleString()), st.get("tuple"));
  }
  @Test
  public void testTypeCheckingVisitorSimple() throws IOException, ParseException {
    final String source =
        "count: table sum of int;\ntotal: table sum of float;\nsum_of_squares: table sum of float;\nx: float = input;\nemit count <- 1;\nemit total <- x;\nemit sum_of_squares <- x * x;\n";

    final SymbolTable st = new SymbolTable();

    SizzleParser.ReInit(new StringReader(source));
    TestTypeCheckingVisitor.typeChecker.visit(SizzleParser.Start(), st);

    Assert.assertEquals(
        "count is not an unweighted, unindexed table of ints",
        new SizzleTable(new SizzleInt()),
        st.get("count"));
    Assert.assertEquals(
        "total is not an unweighted, unindexed stable of floats",
        new SizzleTable(new SizzleFloat()),
        st.get("total"));
    Assert.assertEquals(
        "sum_of_squares is not an unweighted, unindexed table of floats",
        new SizzleTable(new SizzleFloat()),
        st.get("sum_of_squares"));
    Assert.assertEquals("x is not a float", new SizzleFloat(), st.get("x"));
  }